Procházet zdrojové kódy

Merge branch 'giza-protobuf-and-query-node' into distributor-node

Leszek Wiesner před 3 roky
rodič
revize
7c1eec4dcf
100 změnil soubory, kde provedl 4205 přidání a 8651 odebrání
  1. 0 28
      .github/workflows/content-metadata.yml
  2. 2 2
      .github/workflows/joystream-cli.yml
  3. 22 0
      .github/workflows/metadata-protobuf.yml
  4. 0 6
      .github/workflows/query-node.yml
  5. 1 1
      .github/workflows/run-network-tests.yml
  6. 1 1
      apps.Dockerfile
  7. 1 1
      build-npm-packages.sh
  8. 1 1
      cli/package.json
  9. 0 4
      content-metadata-protobuf/.eslintignore
  10. 0 16
      content-metadata-protobuf/.eslintrc.js
  11. 0 2
      content-metadata-protobuf/.gitignore
  12. 0 4
      content-metadata-protobuf/.prettierignore
  13. 0 53
      content-metadata-protobuf/README.md
  14. 0 15
      content-metadata-protobuf/compile.sh
  15. 0 85
      content-metadata-protobuf/compiled/proto/Channel_pb.d.ts
  16. 0 646
      content-metadata-protobuf/compiled/proto/Channel_pb.js
  17. 0 57
      content-metadata-protobuf/compiled/proto/Person_pb.d.ts
  18. 0 428
      content-metadata-protobuf/compiled/proto/Person_pb.js
  19. 0 33
      content-metadata-protobuf/compiled/proto/Playlist_pb.d.ts
  20. 0 246
      content-metadata-protobuf/compiled/proto/Playlist_pb.js
  21. 0 85
      content-metadata-protobuf/compiled/proto/Series_pb.d.ts
  22. 0 666
      content-metadata-protobuf/compiled/proto/Series_pb.js
  23. 0 235
      content-metadata-protobuf/compiled/proto/Video_pb.d.ts
  24. 0 1847
      content-metadata-protobuf/compiled/proto/Video_pb.js
  25. 0 374
      content-metadata-protobuf/doc/index.md
  26. 0 13
      content-metadata-protobuf/generate-md-doc.sh
  27. 0 47
      content-metadata-protobuf/package.json
  28. 0 10
      content-metadata-protobuf/src/index.ts
  29. 0 33
      content-metadata-protobuf/test/channel.ts
  30. 0 115
      content-metadata-protobuf/test/video.ts
  31. 0 15
      content-metadata-protobuf/tsconfig.json
  32. 1 0
      metadata-protobuf/.gitignore
  33. 5 7
      metadata-protobuf/README.md
  34. 1421 203
      metadata-protobuf/compiled/index.d.ts
  35. 450 315
      metadata-protobuf/compiled/index.js
  36. 0 0
      metadata-protobuf/doc-appendix.md
  37. 351 6
      metadata-protobuf/doc/index.md
  38. 3 0
      metadata-protobuf/generate-md-doc.sh
  39. 4 2
      metadata-protobuf/package.json
  40. 0 0
      metadata-protobuf/proto/Channel.proto
  41. 0 0
      metadata-protobuf/proto/Person.proto
  42. 0 0
      metadata-protobuf/proto/Playlist.proto
  43. 0 0
      metadata-protobuf/proto/Series.proto
  44. 0 0
      metadata-protobuf/proto/Video.proto
  45. 0 0
      metadata-protobuf/src/KnownLicenses.json
  46. 4 10
      metadata-protobuf/src/licenses.ts
  47. 2 2
      metadata-protobuf/src/types.ts
  48. 8 2
      metadata-protobuf/src/utils.ts
  49. 31 0
      metadata-protobuf/test/channel.ts
  50. 14 8
      metadata-protobuf/test/license-codes.ts
  51. 87 0
      metadata-protobuf/test/video.ts
  52. 0 1
      package.json
  53. 135 207
      query-node/manifest.yml
  54. 1 0
      query-node/mappings/.eslintignore
  55. 1 0
      query-node/mappings/.prettierignore
  56. 96 98
      query-node/mappings/common.ts
  57. 230 0
      query-node/mappings/content/channel.ts
  58. 25 26
      query-node/mappings/content/curatorGroup.ts
  59. 0 0
      query-node/mappings/content/index.ts
  60. 466 0
      query-node/mappings/content/utils.ts
  61. 271 0
      query-node/mappings/content/video.ts
  62. 8 0
      query-node/mappings/genesis-data/index.ts
  63. 0 0
      query-node/mappings/genesis-data/members.json
  64. 10 0
      query-node/mappings/genesis-data/storageSystem.json
  65. 20 0
      query-node/mappings/genesis-data/types.ts
  66. 35 0
      query-node/mappings/genesis.ts
  67. 0 63
      query-node/mappings/giza/common.ts
  68. 0 3
      query-node/mappings/giza/genesis-data/index.ts
  69. 0 1
      query-node/mappings/giza/genesis-data/storageSystem.json
  70. 0 12
      query-node/mappings/giza/genesis.ts
  71. 0 2
      query-node/mappings/giza/index.ts
  72. 3 2
      query-node/mappings/index.ts
  73. 37 45
      query-node/mappings/membership.ts
  74. 2 2
      query-node/mappings/package.json
  75. 101 72
      query-node/mappings/storage/index.ts
  76. 0 0
      query-node/mappings/storage/metadata.ts
  77. 0 1
      query-node/mappings/sumer/bootstrap/data/workers.json
  78. 0 69
      query-node/mappings/sumer/bootstrap/index.ts
  79. 0 42
      query-node/mappings/sumer/bootstrap/members.ts
  80. 0 48
      query-node/mappings/sumer/bootstrap/workers.ts
  81. 0 279
      query-node/mappings/sumer/content/channel.ts
  82. 0 773
      query-node/mappings/sumer/content/utils.ts
  83. 0 498
      query-node/mappings/sumer/content/video.ts
  84. 0 6
      query-node/mappings/sumer/eventFix.ts
  85. 0 280
      query-node/mappings/sumer/storage.ts
  86. 0 237
      query-node/mappings/sumer/workingGroup.ts
  87. 1 1
      query-node/mappings/tsconfig.json
  88. 153 0
      query-node/mappings/workingGroup.ts
  89. 28 182
      query-node/schemas/content.graphql
  90. 21 20
      query-node/schemas/storage.graphql
  91. 17 0
      query-node/schemas/workingGroups.graphql
  92. 22 3
      runtime-modules/storage/src/lib.rs
  93. 2 0
      runtime-modules/storage/src/tests/mocks.rs
  94. 29 33
      runtime-modules/storage/src/tests/mod.rs
  95. 2 0
      runtime/src/lib.rs
  96. 1 1
      storage-node-v2/package.json
  97. 6 0
      storage-node-v2/src/api-spec/openapi.yaml
  98. 4 1
      storage-node-v2/src/commands/server.ts
  99. 22 6
      storage-node-v2/src/services/webApi/app.ts
  100. 47 13
      storage-node-v2/src/services/webApi/controllers/publicApi.ts

+ 0 - 28
.github/workflows/content-metadata.yml

@@ -1,28 +0,0 @@
-name: content-metadata
-on: [pull_request, push]
-
-jobs:
-  schemas_checks:
-    name: Checks
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        node-version: [14.x]
-    steps:
-    - uses: actions/checkout@v1
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v1
-      with:
-        node-version: ${{ matrix.node-version }}
-    - name: test protobuf
-      run: |
-        # # Install protoc compiler
-        # sudo apt-get install -y protobuf-compiler
-        # protoc --version
-        # # Install documentation plugin
-        # sudo apt-get install -y golang-go
-        # go get -u github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc
-        yarn install --frozen-lockfile
-        yarn workspace @joystream/content-metadata-protobuf build:ts
-        yarn workspace @joystream/content-metadata-protobuf checks --quiet
-        yarn workspace @joystream/content-metadata-protobuf test

+ 2 - 2
.github/workflows/joystream-cli.yml

@@ -18,7 +18,7 @@ jobs:
       run: |
         yarn install --frozen-lockfile
         yarn workspace @joystream/types build
-        yarn workspace @joystream/content-metadata-protobuf build:ts
+        yarn workspace @joystream/metadata-protobuf build
         yarn workspace @joystream/cli checks --quiet
     - name: yarn pack test
       run: |
@@ -42,7 +42,7 @@ jobs:
       run: |
         yarn install --frozen-lockfile --network-timeout 120000
         yarn workspace @joystream/types build
-        yarn workspace @joystream/content-metadata-protobuf build:ts
+        yarn workspace @joystream/metadata-protobuf build
         yarn workspace @joystream/cli checks --quiet
     - name: yarn pack test
       run: |

+ 22 - 0
.github/workflows/metadata-protobuf.yml

@@ -0,0 +1,22 @@
+name: metadata-protobuf
+on: [pull_request, push]
+
+jobs:
+  schemas_checks:
+    name: Checks
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        node-version: [14.x]
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: test protobuf
+      run: |
+        yarn install --frozen-lockfile
+        yarn workspace @joystream/metadata-protobuf build
+        yarn workspace @joystream/metadata-protobuf checks --quiet
+        yarn workspace @joystream/metadata-protobuf test

+ 0 - 6
.github/workflows/query-node.yml

@@ -17,9 +17,6 @@ jobs:
     - name: checks
       run: |
         yarn install --frozen-lockfile
-        yarn workspace @joystream/types build
-        yarn workspace @joystream/content-metadata-protobuf build:ts
-        ./query-node/build.sh
         yarn workspace query-node-mappings checks --quiet
 
   query_node_build_osx:
@@ -37,7 +34,4 @@ jobs:
     - name: checks
       run: |
         yarn install --frozen-lockfile --network-timeout 120000
-        yarn workspace @joystream/types build
-        yarn workspace @joystream/content-metadata-protobuf build:ts
-        ./query-node/build.sh
         yarn workspace query-node-mappings checks --quiet

+ 1 - 1
.github/workflows/run-network-tests.yml

@@ -152,7 +152,7 @@ jobs:
         run: |
           yarn install --frozen-lockfile
           yarn workspace @joystream/types build
-          yarn workspace @joystream/content-metadata-protobuf build:ts
+          yarn workspace @joystream/metadata-protobuf build
       - name: Ensure query-node builds
         run: yarn workspace query-node-root build
       - name: Ensure tests are runnable

+ 1 - 1
apps.Dockerfile

@@ -9,7 +9,7 @@ RUN  rm -fr /joystream/pioneer
 RUN yarn --forzen-lockfile
 
 RUN yarn workspace @joystream/types build
-RUN yarn workspace @joystream/content-metadata-protobuf build:ts
+RUN yarn workspace @joystream/metadata-protobuf build
 RUN yarn workspace query-node-root build
 RUN yarn workspace storage-node build
 

+ 1 - 1
build-npm-packages.sh

@@ -4,7 +4,7 @@ set -e
 
 yarn
 yarn workspace @joystream/types build
-yarn workspace @joystream/content-metadata-protobuf build:ts
+yarn workspace @joystream/metadata-protobuf build
 yarn workspace query-node-root build
 yarn workspace @joystream/cli build
 yarn workspace storage-node build

+ 1 - 1
cli/package.json

@@ -10,7 +10,7 @@
   "dependencies": {
     "@apidevtools/json-schema-ref-parser": "^9.0.6",
     "@ffprobe-installer/ffprobe": "^1.1.0",
-    "@joystream/content-metadata-protobuf": "^1.1.0",
+    "@joystream/metadata-protobuf": "^1.0.0",
     "@joystream/types": "^0.16.1",
     "@oclif/command": "^1.5.19",
     "@oclif/config": "^1.14.0",

+ 0 - 4
content-metadata-protobuf/.eslintignore

@@ -1,4 +0,0 @@
-lib/
-proto/
-compiled/
-.eslintrc.js

+ 0 - 16
content-metadata-protobuf/.eslintrc.js

@@ -1,16 +0,0 @@
-module.exports = {
-  env: {
-    mocha: true,
-  },
-  parserOptions: {
-    project: './tsconfig.json'
-  },
-  extends: [
-    '@joystream/eslint-config'
-  ],
-  rules: {
-    'no-unused-vars': 'off', // Required by the typescript rule below
-    '@typescript-eslint/no-unused-vars': ['error'],
-    '@typescript-eslint/no-floating-promises': 'error',
-  },
-}

+ 0 - 2
content-metadata-protobuf/.gitignore

@@ -1,2 +0,0 @@
-node_modules/
-lib/

+ 0 - 4
content-metadata-protobuf/.prettierignore

@@ -1,4 +0,0 @@
-lib/
-doc/
-proto/
-compiled/

+ 0 - 53
content-metadata-protobuf/README.md

@@ -1,53 +0,0 @@
-## Joystream Content Directory Metadata Library
-
-This package contains protobuf message definitions compiled to Javascript/Typescript used for creating and updating various metadata blobs in the joystream content directory.
-
-### Message Specs
-
-Documented in [doc](./doc) folder
-
-### Choice of protobuf protocol v2
-
-For our usecase we wish to re-use same message to create and update  subset of fields.
-For this reason we need the explicit information about wether a field has been set or not and this is only possible with proto v2.
-
-Background: required/optional feilds are deprecated in [proto v3](https://www.ben-morris.com/handling-protocol-buffers-backwards-compatibility-between-versions-2-and-3-using-c/)
-
-
-### Helper methods
-The custom Joystream types such as License have helper methods to construct pre-defined well known values.
-
-### Example code:
-
-Best place to look at are the [tests specs](./test)
-
-### Opaque types
-We use simple [ISO_639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code representation for Language.
-useful npm package https://www.npmjs.com/package/iso-639-1
-
-### Building the package
-
-Building will compile the protofiles and build the library from source.
-
-- pre-requisists for compiling protofiles:
-    - [protoc](https://github.com/protocolbuffers/protobuf/releases)
-
-- pre-requisists for generating documentation:
-    - [golang](https://golang.org/)
-    - [protoc-gen-doc](https://github.com/pseudomuto/protoc-gen-doc) to generate docs
-
-```
-yarn && yarn build
-```
-
-### Generating docs
-
-```
-yarn generate-docs
-```
-
-### Tests
-
-```
-yarn test
-```

+ 0 - 15
content-metadata-protobuf/compile.sh

@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-# Path to this plugin
-PROTOC_GEN_TS_PATH="./node_modules/.bin/protoc-gen-ts"
-
-# Directory to write generated code to (.js and .d.ts files)
-OUT_DIR="./compiled"
-mkdir -p ${OUT_DIR}
-
-# Compile proto files
-protoc \
-    --plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}" \
-    --js_out="import_style=commonjs,binary:${OUT_DIR}" \
-    --ts_out="${OUT_DIR}" \
-    proto/*.proto

+ 0 - 85
content-metadata-protobuf/compiled/proto/Channel_pb.d.ts

@@ -1,85 +0,0 @@
-// package: 
-// file: proto/Channel.proto
-
-import * as jspb from "google-protobuf";
-
-export class ChannelMetadata extends jspb.Message {
-  hasTitle(): boolean;
-  clearTitle(): void;
-  getTitle(): string | undefined;
-  setTitle(value: string): void;
-
-  hasDescription(): boolean;
-  clearDescription(): void;
-  getDescription(): string | undefined;
-  setDescription(value: string): void;
-
-  hasIsPublic(): boolean;
-  clearIsPublic(): void;
-  getIsPublic(): boolean | undefined;
-  setIsPublic(value: boolean): void;
-
-  hasLanguage(): boolean;
-  clearLanguage(): void;
-  getLanguage(): string | undefined;
-  setLanguage(value: string): void;
-
-  hasCoverPhoto(): boolean;
-  clearCoverPhoto(): void;
-  getCoverPhoto(): number | undefined;
-  setCoverPhoto(value: number): void;
-
-  hasAvatarPhoto(): boolean;
-  clearAvatarPhoto(): void;
-  getAvatarPhoto(): number | undefined;
-  setAvatarPhoto(value: number): void;
-
-  hasCategory(): boolean;
-  clearCategory(): void;
-  getCategory(): number | undefined;
-  setCategory(value: number): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): ChannelMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: ChannelMetadata): ChannelMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: ChannelMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): ChannelMetadata;
-  static deserializeBinaryFromReader(message: ChannelMetadata, reader: jspb.BinaryReader): ChannelMetadata;
-}
-
-export namespace ChannelMetadata {
-  export type AsObject = {
-    title?: string,
-    description?: string,
-    isPublic?: boolean,
-    language?: string,
-    coverPhoto?: number,
-    avatarPhoto?: number,
-    category?: number,
-  }
-}
-
-export class ChannelCategoryMetadata extends jspb.Message {
-  hasName(): boolean;
-  clearName(): void;
-  getName(): string | undefined;
-  setName(value: string): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): ChannelCategoryMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: ChannelCategoryMetadata): ChannelCategoryMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: ChannelCategoryMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): ChannelCategoryMetadata;
-  static deserializeBinaryFromReader(message: ChannelCategoryMetadata, reader: jspb.BinaryReader): ChannelCategoryMetadata;
-}
-
-export namespace ChannelCategoryMetadata {
-  export type AsObject = {
-    name?: string,
-  }
-}
-

+ 0 - 646
content-metadata-protobuf/compiled/proto/Channel_pb.js

@@ -1,646 +0,0 @@
-// source: proto/Channel.proto
-/**
- * @fileoverview
- * @enhanceable
- * @suppress {missingRequire} reports error on implicit type usages.
- * @suppress {messageConventions} JS Compiler reports an error if a variable or
- *     field starts with 'MSG_' and isn't a translatable message.
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-/* eslint-disable */
-// @ts-nocheck
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.ChannelCategoryMetadata', null, global);
-goog.exportSymbol('proto.ChannelMetadata', null, global);
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.ChannelMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.ChannelMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.ChannelMetadata.displayName = 'proto.ChannelMetadata';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.ChannelCategoryMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.ChannelCategoryMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.ChannelCategoryMetadata.displayName = 'proto.ChannelCategoryMetadata';
-}
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.ChannelMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.ChannelMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.ChannelMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.ChannelMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    title: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    description: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    isPublic: (f = jspb.Message.getBooleanField(msg, 3)) == null ? undefined : f,
-    language: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f,
-    coverPhoto: (f = jspb.Message.getField(msg, 5)) == null ? undefined : f,
-    avatarPhoto: (f = jspb.Message.getField(msg, 6)) == null ? undefined : f,
-    category: (f = jspb.Message.getField(msg, 7)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.ChannelMetadata}
- */
-proto.ChannelMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.ChannelMetadata;
-  return proto.ChannelMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.ChannelMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.ChannelMetadata}
- */
-proto.ChannelMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setTitle(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setDescription(value);
-      break;
-    case 3:
-      var value = /** @type {boolean} */ (reader.readBool());
-      msg.setIsPublic(value);
-      break;
-    case 4:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setLanguage(value);
-      break;
-    case 5:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setCoverPhoto(value);
-      break;
-    case 6:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setAvatarPhoto(value);
-      break;
-    case 7:
-      var value = /** @type {number} */ (reader.readUint64());
-      msg.setCategory(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.ChannelMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.ChannelMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.ChannelMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.ChannelMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {boolean} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeBool(
-      3,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 4));
-  if (f != null) {
-    writer.writeString(
-      4,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 5));
-  if (f != null) {
-    writer.writeUint32(
-      5,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 6));
-  if (f != null) {
-    writer.writeUint32(
-      6,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 7));
-  if (f != null) {
-    writer.writeUint64(
-      7,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string title = 1;
- * @return {string}
- */
-proto.ChannelMetadata.prototype.getTitle = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setTitle = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearTitle = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasTitle = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string description = 2;
- * @return {string}
- */
-proto.ChannelMetadata.prototype.getDescription = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setDescription = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearDescription = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasDescription = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional bool is_public = 3;
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.getIsPublic = function() {
-  return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
-};
-
-
-/**
- * @param {boolean} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setIsPublic = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearIsPublic = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasIsPublic = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-/**
- * optional string language = 4;
- * @return {string}
- */
-proto.ChannelMetadata.prototype.getLanguage = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setLanguage = function(value) {
-  return jspb.Message.setField(this, 4, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearLanguage = function() {
-  return jspb.Message.setField(this, 4, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasLanguage = function() {
-  return jspb.Message.getField(this, 4) != null;
-};
-
-
-/**
- * optional uint32 cover_photo = 5;
- * @return {number}
- */
-proto.ChannelMetadata.prototype.getCoverPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setCoverPhoto = function(value) {
-  return jspb.Message.setField(this, 5, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearCoverPhoto = function() {
-  return jspb.Message.setField(this, 5, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasCoverPhoto = function() {
-  return jspb.Message.getField(this, 5) != null;
-};
-
-
-/**
- * optional uint32 avatar_photo = 6;
- * @return {number}
- */
-proto.ChannelMetadata.prototype.getAvatarPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 6, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setAvatarPhoto = function(value) {
-  return jspb.Message.setField(this, 6, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearAvatarPhoto = function() {
-  return jspb.Message.setField(this, 6, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasAvatarPhoto = function() {
-  return jspb.Message.getField(this, 6) != null;
-};
-
-
-/**
- * optional uint64 category = 7;
- * @return {number}
- */
-proto.ChannelMetadata.prototype.getCategory = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.setCategory = function(value) {
-  return jspb.Message.setField(this, 7, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelMetadata} returns this
- */
-proto.ChannelMetadata.prototype.clearCategory = function() {
-  return jspb.Message.setField(this, 7, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelMetadata.prototype.hasCategory = function() {
-  return jspb.Message.getField(this, 7) != null;
-};
-
-
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.ChannelCategoryMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.ChannelCategoryMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.ChannelCategoryMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.ChannelCategoryMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    name: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.ChannelCategoryMetadata}
- */
-proto.ChannelCategoryMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.ChannelCategoryMetadata;
-  return proto.ChannelCategoryMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.ChannelCategoryMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.ChannelCategoryMetadata}
- */
-proto.ChannelCategoryMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setName(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.ChannelCategoryMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.ChannelCategoryMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.ChannelCategoryMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.ChannelCategoryMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string name = 1;
- * @return {string}
- */
-proto.ChannelCategoryMetadata.prototype.getName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.ChannelCategoryMetadata} returns this
- */
-proto.ChannelCategoryMetadata.prototype.setName = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.ChannelCategoryMetadata} returns this
- */
-proto.ChannelCategoryMetadata.prototype.clearName = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.ChannelCategoryMetadata.prototype.hasName = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-goog.object.extend(exports, proto);

+ 0 - 57
content-metadata-protobuf/compiled/proto/Person_pb.d.ts

@@ -1,57 +0,0 @@
-// package: 
-// file: proto/Person.proto
-
-import * as jspb from "google-protobuf";
-
-export class PersonMetadata extends jspb.Message {
-  hasFirstName(): boolean;
-  clearFirstName(): void;
-  getFirstName(): string | undefined;
-  setFirstName(value: string): void;
-
-  hasMiddleName(): boolean;
-  clearMiddleName(): void;
-  getMiddleName(): string | undefined;
-  setMiddleName(value: string): void;
-
-  hasLastName(): boolean;
-  clearLastName(): void;
-  getLastName(): string | undefined;
-  setLastName(value: string): void;
-
-  hasAbout(): boolean;
-  clearAbout(): void;
-  getAbout(): string | undefined;
-  setAbout(value: string): void;
-
-  hasCoverPhoto(): boolean;
-  clearCoverPhoto(): void;
-  getCoverPhoto(): number | undefined;
-  setCoverPhoto(value: number): void;
-
-  hasAvatarPhoto(): boolean;
-  clearAvatarPhoto(): void;
-  getAvatarPhoto(): number | undefined;
-  setAvatarPhoto(value: number): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): PersonMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: PersonMetadata): PersonMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: PersonMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): PersonMetadata;
-  static deserializeBinaryFromReader(message: PersonMetadata, reader: jspb.BinaryReader): PersonMetadata;
-}
-
-export namespace PersonMetadata {
-  export type AsObject = {
-    firstName?: string,
-    middleName?: string,
-    lastName?: string,
-    about?: string,
-    coverPhoto?: number,
-    avatarPhoto?: number,
-  }
-}
-

+ 0 - 428
content-metadata-protobuf/compiled/proto/Person_pb.js

@@ -1,428 +0,0 @@
-// source: proto/Person.proto
-/**
- * @fileoverview
- * @enhanceable
- * @suppress {missingRequire} reports error on implicit type usages.
- * @suppress {messageConventions} JS Compiler reports an error if a variable or
- *     field starts with 'MSG_' and isn't a translatable message.
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-/* eslint-disable */
-// @ts-nocheck
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.PersonMetadata', null, global);
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.PersonMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.PersonMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.PersonMetadata.displayName = 'proto.PersonMetadata';
-}
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.PersonMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.PersonMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.PersonMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PersonMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    firstName: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    middleName: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    lastName: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
-    about: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f,
-    coverPhoto: (f = jspb.Message.getField(msg, 5)) == null ? undefined : f,
-    avatarPhoto: (f = jspb.Message.getField(msg, 6)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.PersonMetadata}
- */
-proto.PersonMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.PersonMetadata;
-  return proto.PersonMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.PersonMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.PersonMetadata}
- */
-proto.PersonMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setFirstName(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setMiddleName(value);
-      break;
-    case 3:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setLastName(value);
-      break;
-    case 4:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setAbout(value);
-      break;
-    case 5:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setCoverPhoto(value);
-      break;
-    case 6:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setAvatarPhoto(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.PersonMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.PersonMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.PersonMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PersonMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeString(
-      3,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 4));
-  if (f != null) {
-    writer.writeString(
-      4,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 5));
-  if (f != null) {
-    writer.writeUint32(
-      5,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 6));
-  if (f != null) {
-    writer.writeUint32(
-      6,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string first_name = 1;
- * @return {string}
- */
-proto.PersonMetadata.prototype.getFirstName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setFirstName = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearFirstName = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasFirstName = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string middle_name = 2;
- * @return {string}
- */
-proto.PersonMetadata.prototype.getMiddleName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setMiddleName = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearMiddleName = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasMiddleName = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional string last_name = 3;
- * @return {string}
- */
-proto.PersonMetadata.prototype.getLastName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setLastName = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearLastName = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasLastName = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-/**
- * optional string about = 4;
- * @return {string}
- */
-proto.PersonMetadata.prototype.getAbout = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setAbout = function(value) {
-  return jspb.Message.setField(this, 4, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearAbout = function() {
-  return jspb.Message.setField(this, 4, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasAbout = function() {
-  return jspb.Message.getField(this, 4) != null;
-};
-
-
-/**
- * optional uint32 cover_photo = 5;
- * @return {number}
- */
-proto.PersonMetadata.prototype.getCoverPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setCoverPhoto = function(value) {
-  return jspb.Message.setField(this, 5, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearCoverPhoto = function() {
-  return jspb.Message.setField(this, 5, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasCoverPhoto = function() {
-  return jspb.Message.getField(this, 5) != null;
-};
-
-
-/**
- * optional uint32 avatar_photo = 6;
- * @return {number}
- */
-proto.PersonMetadata.prototype.getAvatarPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 6, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.setAvatarPhoto = function(value) {
-  return jspb.Message.setField(this, 6, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PersonMetadata} returns this
- */
-proto.PersonMetadata.prototype.clearAvatarPhoto = function() {
-  return jspb.Message.setField(this, 6, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PersonMetadata.prototype.hasAvatarPhoto = function() {
-  return jspb.Message.getField(this, 6) != null;
-};
-
-
-goog.object.extend(exports, proto);

+ 0 - 33
content-metadata-protobuf/compiled/proto/Playlist_pb.d.ts

@@ -1,33 +0,0 @@
-// package: 
-// file: proto/Playlist.proto
-
-import * as jspb from "google-protobuf";
-
-export class PlaylistMetadata extends jspb.Message {
-  hasTitle(): boolean;
-  clearTitle(): void;
-  getTitle(): string | undefined;
-  setTitle(value: string): void;
-
-  clearVideosList(): void;
-  getVideosList(): Array<number>;
-  setVideosList(value: Array<number>): void;
-  addVideos(value: number, index?: number): number;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): PlaylistMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: PlaylistMetadata): PlaylistMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: PlaylistMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): PlaylistMetadata;
-  static deserializeBinaryFromReader(message: PlaylistMetadata, reader: jspb.BinaryReader): PlaylistMetadata;
-}
-
-export namespace PlaylistMetadata {
-  export type AsObject = {
-    title?: string,
-    videosList: Array<number>,
-  }
-}
-

+ 0 - 246
content-metadata-protobuf/compiled/proto/Playlist_pb.js

@@ -1,246 +0,0 @@
-// source: proto/Playlist.proto
-/**
- * @fileoverview
- * @enhanceable
- * @suppress {missingRequire} reports error on implicit type usages.
- * @suppress {messageConventions} JS Compiler reports an error if a variable or
- *     field starts with 'MSG_' and isn't a translatable message.
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-/* eslint-disable */
-// @ts-nocheck
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.PlaylistMetadata', null, global);
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.PlaylistMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, proto.PlaylistMetadata.repeatedFields_, null);
-};
-goog.inherits(proto.PlaylistMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.PlaylistMetadata.displayName = 'proto.PlaylistMetadata';
-}
-
-/**
- * List of repeated fields within this message type.
- * @private {!Array<number>}
- * @const
- */
-proto.PlaylistMetadata.repeatedFields_ = [2];
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.PlaylistMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.PlaylistMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.PlaylistMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PlaylistMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    title: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    videosList: (f = jspb.Message.getRepeatedField(msg, 2)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.PlaylistMetadata}
- */
-proto.PlaylistMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.PlaylistMetadata;
-  return proto.PlaylistMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.PlaylistMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.PlaylistMetadata}
- */
-proto.PlaylistMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setTitle(value);
-      break;
-    case 2:
-      var values = /** @type {!Array<number>} */ (reader.isDelimited() ? reader.readPackedUint64() : [reader.readUint64()]);
-      for (var i = 0; i < values.length; i++) {
-        msg.addVideos(values[i]);
-      }
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.PlaylistMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.PlaylistMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.PlaylistMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PlaylistMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = message.getVideosList();
-  if (f.length > 0) {
-    writer.writeRepeatedUint64(
-      2,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string title = 1;
- * @return {string}
- */
-proto.PlaylistMetadata.prototype.getTitle = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PlaylistMetadata} returns this
- */
-proto.PlaylistMetadata.prototype.setTitle = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PlaylistMetadata} returns this
- */
-proto.PlaylistMetadata.prototype.clearTitle = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PlaylistMetadata.prototype.hasTitle = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * repeated uint64 videos = 2;
- * @return {!Array<number>}
- */
-proto.PlaylistMetadata.prototype.getVideosList = function() {
-  return /** @type {!Array<number>} */ (jspb.Message.getRepeatedField(this, 2));
-};
-
-
-/**
- * @param {!Array<number>} value
- * @return {!proto.PlaylistMetadata} returns this
- */
-proto.PlaylistMetadata.prototype.setVideosList = function(value) {
-  return jspb.Message.setField(this, 2, value || []);
-};
-
-
-/**
- * @param {number} value
- * @param {number=} opt_index
- * @return {!proto.PlaylistMetadata} returns this
- */
-proto.PlaylistMetadata.prototype.addVideos = function(value, opt_index) {
-  return jspb.Message.addToRepeatedField(this, 2, value, opt_index);
-};
-
-
-/**
- * Clears the list making it empty but non-null.
- * @return {!proto.PlaylistMetadata} returns this
- */
-proto.PlaylistMetadata.prototype.clearVideosList = function() {
-  return this.setVideosList([]);
-};
-
-
-goog.object.extend(exports, proto);

+ 0 - 85
content-metadata-protobuf/compiled/proto/Series_pb.d.ts

@@ -1,85 +0,0 @@
-// package: 
-// file: proto/Series.proto
-
-import * as jspb from "google-protobuf";
-
-export class SeriesMetadata extends jspb.Message {
-  hasTitle(): boolean;
-  clearTitle(): void;
-  getTitle(): string | undefined;
-  setTitle(value: string): void;
-
-  hasDescription(): boolean;
-  clearDescription(): void;
-  getDescription(): string | undefined;
-  setDescription(value: string): void;
-
-  hasCoverPhoto(): boolean;
-  clearCoverPhoto(): void;
-  getCoverPhoto(): number | undefined;
-  setCoverPhoto(value: number): void;
-
-  clearPersonsList(): void;
-  getPersonsList(): Array<number>;
-  setPersonsList(value: Array<number>): void;
-  addPersons(value: number, index?: number): number;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): SeriesMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: SeriesMetadata): SeriesMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: SeriesMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): SeriesMetadata;
-  static deserializeBinaryFromReader(message: SeriesMetadata, reader: jspb.BinaryReader): SeriesMetadata;
-}
-
-export namespace SeriesMetadata {
-  export type AsObject = {
-    title?: string,
-    description?: string,
-    coverPhoto?: number,
-    personsList: Array<number>,
-  }
-}
-
-export class SeasonMetadata extends jspb.Message {
-  hasTitle(): boolean;
-  clearTitle(): void;
-  getTitle(): string | undefined;
-  setTitle(value: string): void;
-
-  hasDescription(): boolean;
-  clearDescription(): void;
-  getDescription(): string | undefined;
-  setDescription(value: string): void;
-
-  hasCoverPhoto(): boolean;
-  clearCoverPhoto(): void;
-  getCoverPhoto(): number | undefined;
-  setCoverPhoto(value: number): void;
-
-  clearPersonsList(): void;
-  getPersonsList(): Array<number>;
-  setPersonsList(value: Array<number>): void;
-  addPersons(value: number, index?: number): number;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): SeasonMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: SeasonMetadata): SeasonMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: SeasonMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): SeasonMetadata;
-  static deserializeBinaryFromReader(message: SeasonMetadata, reader: jspb.BinaryReader): SeasonMetadata;
-}
-
-export namespace SeasonMetadata {
-  export type AsObject = {
-    title?: string,
-    description?: string,
-    coverPhoto?: number,
-    personsList: Array<number>,
-  }
-}
-

+ 0 - 666
content-metadata-protobuf/compiled/proto/Series_pb.js

@@ -1,666 +0,0 @@
-// source: proto/Series.proto
-/**
- * @fileoverview
- * @enhanceable
- * @suppress {missingRequire} reports error on implicit type usages.
- * @suppress {messageConventions} JS Compiler reports an error if a variable or
- *     field starts with 'MSG_' and isn't a translatable message.
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-/* eslint-disable */
-// @ts-nocheck
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.SeasonMetadata', null, global);
-goog.exportSymbol('proto.SeriesMetadata', null, global);
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.SeriesMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, proto.SeriesMetadata.repeatedFields_, null);
-};
-goog.inherits(proto.SeriesMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.SeriesMetadata.displayName = 'proto.SeriesMetadata';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.SeasonMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, proto.SeasonMetadata.repeatedFields_, null);
-};
-goog.inherits(proto.SeasonMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.SeasonMetadata.displayName = 'proto.SeasonMetadata';
-}
-
-/**
- * List of repeated fields within this message type.
- * @private {!Array<number>}
- * @const
- */
-proto.SeriesMetadata.repeatedFields_ = [4];
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.SeriesMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.SeriesMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.SeriesMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.SeriesMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    title: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    description: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    coverPhoto: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
-    personsList: (f = jspb.Message.getRepeatedField(msg, 4)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.SeriesMetadata}
- */
-proto.SeriesMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.SeriesMetadata;
-  return proto.SeriesMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.SeriesMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.SeriesMetadata}
- */
-proto.SeriesMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setTitle(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setDescription(value);
-      break;
-    case 3:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setCoverPhoto(value);
-      break;
-    case 4:
-      var values = /** @type {!Array<number>} */ (reader.isDelimited() ? reader.readPackedUint64() : [reader.readUint64()]);
-      for (var i = 0; i < values.length; i++) {
-        msg.addPersons(values[i]);
-      }
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.SeriesMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.SeriesMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.SeriesMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.SeriesMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeUint32(
-      3,
-      f
-    );
-  }
-  f = message.getPersonsList();
-  if (f.length > 0) {
-    writer.writePackedUint64(
-      4,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string title = 1;
- * @return {string}
- */
-proto.SeriesMetadata.prototype.getTitle = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.setTitle = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.clearTitle = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeriesMetadata.prototype.hasTitle = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string description = 2;
- * @return {string}
- */
-proto.SeriesMetadata.prototype.getDescription = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.setDescription = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.clearDescription = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeriesMetadata.prototype.hasDescription = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional uint32 cover_photo = 3;
- * @return {number}
- */
-proto.SeriesMetadata.prototype.getCoverPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.setCoverPhoto = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.clearCoverPhoto = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeriesMetadata.prototype.hasCoverPhoto = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-/**
- * repeated uint64 persons = 4;
- * @return {!Array<number>}
- */
-proto.SeriesMetadata.prototype.getPersonsList = function() {
-  return /** @type {!Array<number>} */ (jspb.Message.getRepeatedField(this, 4));
-};
-
-
-/**
- * @param {!Array<number>} value
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.setPersonsList = function(value) {
-  return jspb.Message.setField(this, 4, value || []);
-};
-
-
-/**
- * @param {number} value
- * @param {number=} opt_index
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.addPersons = function(value, opt_index) {
-  return jspb.Message.addToRepeatedField(this, 4, value, opt_index);
-};
-
-
-/**
- * Clears the list making it empty but non-null.
- * @return {!proto.SeriesMetadata} returns this
- */
-proto.SeriesMetadata.prototype.clearPersonsList = function() {
-  return this.setPersonsList([]);
-};
-
-
-
-/**
- * List of repeated fields within this message type.
- * @private {!Array<number>}
- * @const
- */
-proto.SeasonMetadata.repeatedFields_ = [4];
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.SeasonMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.SeasonMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.SeasonMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.SeasonMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    title: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    description: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    coverPhoto: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
-    personsList: (f = jspb.Message.getRepeatedField(msg, 4)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.SeasonMetadata}
- */
-proto.SeasonMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.SeasonMetadata;
-  return proto.SeasonMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.SeasonMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.SeasonMetadata}
- */
-proto.SeasonMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setTitle(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setDescription(value);
-      break;
-    case 3:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setCoverPhoto(value);
-      break;
-    case 4:
-      var values = /** @type {!Array<number>} */ (reader.isDelimited() ? reader.readPackedUint64() : [reader.readUint64()]);
-      for (var i = 0; i < values.length; i++) {
-        msg.addPersons(values[i]);
-      }
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.SeasonMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.SeasonMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.SeasonMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.SeasonMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeUint32(
-      3,
-      f
-    );
-  }
-  f = message.getPersonsList();
-  if (f.length > 0) {
-    writer.writePackedUint64(
-      4,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string title = 1;
- * @return {string}
- */
-proto.SeasonMetadata.prototype.getTitle = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.setTitle = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.clearTitle = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeasonMetadata.prototype.hasTitle = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string description = 2;
- * @return {string}
- */
-proto.SeasonMetadata.prototype.getDescription = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.setDescription = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.clearDescription = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeasonMetadata.prototype.hasDescription = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional uint32 cover_photo = 3;
- * @return {number}
- */
-proto.SeasonMetadata.prototype.getCoverPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.setCoverPhoto = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.clearCoverPhoto = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.SeasonMetadata.prototype.hasCoverPhoto = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-/**
- * repeated uint64 persons = 4;
- * @return {!Array<number>}
- */
-proto.SeasonMetadata.prototype.getPersonsList = function() {
-  return /** @type {!Array<number>} */ (jspb.Message.getRepeatedField(this, 4));
-};
-
-
-/**
- * @param {!Array<number>} value
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.setPersonsList = function(value) {
-  return jspb.Message.setField(this, 4, value || []);
-};
-
-
-/**
- * @param {number} value
- * @param {number=} opt_index
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.addPersons = function(value, opt_index) {
-  return jspb.Message.addToRepeatedField(this, 4, value, opt_index);
-};
-
-
-/**
- * Clears the list making it empty but non-null.
- * @return {!proto.SeasonMetadata} returns this
- */
-proto.SeasonMetadata.prototype.clearPersonsList = function() {
-  return this.setPersonsList([]);
-};
-
-
-goog.object.extend(exports, proto);

+ 0 - 235
content-metadata-protobuf/compiled/proto/Video_pb.d.ts

@@ -1,235 +0,0 @@
-// package: 
-// file: proto/Video.proto
-
-import * as jspb from "google-protobuf";
-
-export class PublishedBeforeJoystream extends jspb.Message {
-  hasIsPublished(): boolean;
-  clearIsPublished(): void;
-  getIsPublished(): boolean | undefined;
-  setIsPublished(value: boolean): void;
-
-  hasDate(): boolean;
-  clearDate(): void;
-  getDate(): string | undefined;
-  setDate(value: string): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): PublishedBeforeJoystream.AsObject;
-  static toObject(includeInstance: boolean, msg: PublishedBeforeJoystream): PublishedBeforeJoystream.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: PublishedBeforeJoystream, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): PublishedBeforeJoystream;
-  static deserializeBinaryFromReader(message: PublishedBeforeJoystream, reader: jspb.BinaryReader): PublishedBeforeJoystream;
-}
-
-export namespace PublishedBeforeJoystream {
-  export type AsObject = {
-    isPublished?: boolean,
-    date?: string,
-  }
-}
-
-export class License extends jspb.Message {
-  hasCode(): boolean;
-  clearCode(): void;
-  getCode(): number | undefined;
-  setCode(value: number): void;
-
-  hasAttribution(): boolean;
-  clearAttribution(): void;
-  getAttribution(): string | undefined;
-  setAttribution(value: string): void;
-
-  hasCustomText(): boolean;
-  clearCustomText(): void;
-  getCustomText(): string | undefined;
-  setCustomText(value: string): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): License.AsObject;
-  static toObject(includeInstance: boolean, msg: License): License.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: License, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): License;
-  static deserializeBinaryFromReader(message: License, reader: jspb.BinaryReader): License;
-}
-
-export namespace License {
-  export type AsObject = {
-    code?: number,
-    attribution?: string,
-    customText?: string,
-  }
-}
-
-export class MediaType extends jspb.Message {
-  hasCodecName(): boolean;
-  clearCodecName(): void;
-  getCodecName(): string | undefined;
-  setCodecName(value: string): void;
-
-  hasContainer(): boolean;
-  clearContainer(): void;
-  getContainer(): string | undefined;
-  setContainer(value: string): void;
-
-  hasMimeMediaType(): boolean;
-  clearMimeMediaType(): void;
-  getMimeMediaType(): string | undefined;
-  setMimeMediaType(value: string): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): MediaType.AsObject;
-  static toObject(includeInstance: boolean, msg: MediaType): MediaType.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: MediaType, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): MediaType;
-  static deserializeBinaryFromReader(message: MediaType, reader: jspb.BinaryReader): MediaType;
-}
-
-export namespace MediaType {
-  export type AsObject = {
-    codecName?: string,
-    container?: string,
-    mimeMediaType?: string,
-  }
-}
-
-export class VideoMetadata extends jspb.Message {
-  hasTitle(): boolean;
-  clearTitle(): void;
-  getTitle(): string | undefined;
-  setTitle(value: string): void;
-
-  hasDescription(): boolean;
-  clearDescription(): void;
-  getDescription(): string | undefined;
-  setDescription(value: string): void;
-
-  hasVideo(): boolean;
-  clearVideo(): void;
-  getVideo(): number | undefined;
-  setVideo(value: number): void;
-
-  hasThumbnailPhoto(): boolean;
-  clearThumbnailPhoto(): void;
-  getThumbnailPhoto(): number | undefined;
-  setThumbnailPhoto(value: number): void;
-
-  hasDuration(): boolean;
-  clearDuration(): void;
-  getDuration(): number | undefined;
-  setDuration(value: number): void;
-
-  hasMediaPixelHeight(): boolean;
-  clearMediaPixelHeight(): void;
-  getMediaPixelHeight(): number | undefined;
-  setMediaPixelHeight(value: number): void;
-
-  hasMediaPixelWidth(): boolean;
-  clearMediaPixelWidth(): void;
-  getMediaPixelWidth(): number | undefined;
-  setMediaPixelWidth(value: number): void;
-
-  hasMediaType(): boolean;
-  clearMediaType(): void;
-  getMediaType(): MediaType | undefined;
-  setMediaType(value?: MediaType): void;
-
-  hasLanguage(): boolean;
-  clearLanguage(): void;
-  getLanguage(): string | undefined;
-  setLanguage(value: string): void;
-
-  hasLicense(): boolean;
-  clearLicense(): void;
-  getLicense(): License | undefined;
-  setLicense(value?: License): void;
-
-  hasPublishedBeforeJoystream(): boolean;
-  clearPublishedBeforeJoystream(): void;
-  getPublishedBeforeJoystream(): PublishedBeforeJoystream | undefined;
-  setPublishedBeforeJoystream(value?: PublishedBeforeJoystream): void;
-
-  hasHasMarketing(): boolean;
-  clearHasMarketing(): void;
-  getHasMarketing(): boolean | undefined;
-  setHasMarketing(value: boolean): void;
-
-  hasIsPublic(): boolean;
-  clearIsPublic(): void;
-  getIsPublic(): boolean | undefined;
-  setIsPublic(value: boolean): void;
-
-  hasIsExplicit(): boolean;
-  clearIsExplicit(): void;
-  getIsExplicit(): boolean | undefined;
-  setIsExplicit(value: boolean): void;
-
-  clearPersonsList(): void;
-  getPersonsList(): Array<number>;
-  setPersonsList(value: Array<number>): void;
-  addPersons(value: number, index?: number): number;
-
-  hasCategory(): boolean;
-  clearCategory(): void;
-  getCategory(): number | undefined;
-  setCategory(value: number): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): VideoMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: VideoMetadata): VideoMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: VideoMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): VideoMetadata;
-  static deserializeBinaryFromReader(message: VideoMetadata, reader: jspb.BinaryReader): VideoMetadata;
-}
-
-export namespace VideoMetadata {
-  export type AsObject = {
-    title?: string,
-    description?: string,
-    video?: number,
-    thumbnailPhoto?: number,
-    duration?: number,
-    mediaPixelHeight?: number,
-    mediaPixelWidth?: number,
-    mediaType?: MediaType.AsObject,
-    language?: string,
-    license?: License.AsObject,
-    publishedBeforeJoystream?: PublishedBeforeJoystream.AsObject,
-    hasMarketing?: boolean,
-    isPublic?: boolean,
-    isExplicit?: boolean,
-    personsList: Array<number>,
-    category?: number,
-  }
-}
-
-export class VideoCategoryMetadata extends jspb.Message {
-  hasName(): boolean;
-  clearName(): void;
-  getName(): string | undefined;
-  setName(value: string): void;
-
-  serializeBinary(): Uint8Array;
-  toObject(includeInstance?: boolean): VideoCategoryMetadata.AsObject;
-  static toObject(includeInstance: boolean, msg: VideoCategoryMetadata): VideoCategoryMetadata.AsObject;
-  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
-  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
-  static serializeBinaryToWriter(message: VideoCategoryMetadata, writer: jspb.BinaryWriter): void;
-  static deserializeBinary(bytes: Uint8Array): VideoCategoryMetadata;
-  static deserializeBinaryFromReader(message: VideoCategoryMetadata, reader: jspb.BinaryReader): VideoCategoryMetadata;
-}
-
-export namespace VideoCategoryMetadata {
-  export type AsObject = {
-    name?: string,
-  }
-}
-

+ 0 - 1847
content-metadata-protobuf/compiled/proto/Video_pb.js

@@ -1,1847 +0,0 @@
-// source: proto/Video.proto
-/**
- * @fileoverview
- * @enhanceable
- * @suppress {missingRequire} reports error on implicit type usages.
- * @suppress {messageConventions} JS Compiler reports an error if a variable or
- *     field starts with 'MSG_' and isn't a translatable message.
- * @public
- */
-// GENERATED CODE -- DO NOT EDIT!
-/* eslint-disable */
-// @ts-nocheck
-
-var jspb = require('google-protobuf');
-var goog = jspb;
-var global = Function('return this')();
-
-goog.exportSymbol('proto.License', null, global);
-goog.exportSymbol('proto.MediaType', null, global);
-goog.exportSymbol('proto.PublishedBeforeJoystream', null, global);
-goog.exportSymbol('proto.VideoCategoryMetadata', null, global);
-goog.exportSymbol('proto.VideoMetadata', null, global);
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.PublishedBeforeJoystream = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.PublishedBeforeJoystream, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.PublishedBeforeJoystream.displayName = 'proto.PublishedBeforeJoystream';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.License = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.License, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.License.displayName = 'proto.License';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.MediaType = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.MediaType, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.MediaType.displayName = 'proto.MediaType';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.VideoMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, proto.VideoMetadata.repeatedFields_, null);
-};
-goog.inherits(proto.VideoMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.VideoMetadata.displayName = 'proto.VideoMetadata';
-}
-/**
- * Generated by JsPbCodeGenerator.
- * @param {Array=} opt_data Optional initial data array, typically from a
- * server response, or constructed directly in Javascript. The array is used
- * in place and becomes part of the constructed object. It is not cloned.
- * If no data is provided, the constructed object will be empty, but still
- * valid.
- * @extends {jspb.Message}
- * @constructor
- */
-proto.VideoCategoryMetadata = function(opt_data) {
-  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
-};
-goog.inherits(proto.VideoCategoryMetadata, jspb.Message);
-if (goog.DEBUG && !COMPILED) {
-  /**
-   * @public
-   * @override
-   */
-  proto.VideoCategoryMetadata.displayName = 'proto.VideoCategoryMetadata';
-}
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.PublishedBeforeJoystream.prototype.toObject = function(opt_includeInstance) {
-  return proto.PublishedBeforeJoystream.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.PublishedBeforeJoystream} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PublishedBeforeJoystream.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    isPublished: (f = jspb.Message.getBooleanField(msg, 1)) == null ? undefined : f,
-    date: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.PublishedBeforeJoystream}
- */
-proto.PublishedBeforeJoystream.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.PublishedBeforeJoystream;
-  return proto.PublishedBeforeJoystream.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.PublishedBeforeJoystream} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.PublishedBeforeJoystream}
- */
-proto.PublishedBeforeJoystream.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {boolean} */ (reader.readBool());
-      msg.setIsPublished(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setDate(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.PublishedBeforeJoystream.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.PublishedBeforeJoystream.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.PublishedBeforeJoystream} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.PublishedBeforeJoystream.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {boolean} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeBool(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-};
-
-
-/**
- * optional bool is_published = 1;
- * @return {boolean}
- */
-proto.PublishedBeforeJoystream.prototype.getIsPublished = function() {
-  return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false));
-};
-
-
-/**
- * @param {boolean} value
- * @return {!proto.PublishedBeforeJoystream} returns this
- */
-proto.PublishedBeforeJoystream.prototype.setIsPublished = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PublishedBeforeJoystream} returns this
- */
-proto.PublishedBeforeJoystream.prototype.clearIsPublished = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PublishedBeforeJoystream.prototype.hasIsPublished = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string date = 2;
- * @return {string}
- */
-proto.PublishedBeforeJoystream.prototype.getDate = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.PublishedBeforeJoystream} returns this
- */
-proto.PublishedBeforeJoystream.prototype.setDate = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.PublishedBeforeJoystream} returns this
- */
-proto.PublishedBeforeJoystream.prototype.clearDate = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.PublishedBeforeJoystream.prototype.hasDate = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.License.prototype.toObject = function(opt_includeInstance) {
-  return proto.License.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.License} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.License.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    code: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    attribution: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    customText: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.License}
- */
-proto.License.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.License;
-  return proto.License.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.License} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.License}
- */
-proto.License.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setCode(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setAttribution(value);
-      break;
-    case 3:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setCustomText(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.License.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.License.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.License} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.License.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {number} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeUint32(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeString(
-      3,
-      f
-    );
-  }
-};
-
-
-/**
- * optional uint32 code = 1;
- * @return {number}
- */
-proto.License.prototype.getCode = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.License} returns this
- */
-proto.License.prototype.setCode = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.License} returns this
- */
-proto.License.prototype.clearCode = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.License.prototype.hasCode = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string attribution = 2;
- * @return {string}
- */
-proto.License.prototype.getAttribution = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.License} returns this
- */
-proto.License.prototype.setAttribution = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.License} returns this
- */
-proto.License.prototype.clearAttribution = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.License.prototype.hasAttribution = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional string custom_text = 3;
- * @return {string}
- */
-proto.License.prototype.getCustomText = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.License} returns this
- */
-proto.License.prototype.setCustomText = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.License} returns this
- */
-proto.License.prototype.clearCustomText = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.License.prototype.hasCustomText = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.MediaType.prototype.toObject = function(opt_includeInstance) {
-  return proto.MediaType.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.MediaType} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.MediaType.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    codecName: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    container: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    mimeMediaType: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.MediaType}
- */
-proto.MediaType.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.MediaType;
-  return proto.MediaType.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.MediaType} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.MediaType}
- */
-proto.MediaType.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setCodecName(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setContainer(value);
-      break;
-    case 3:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setMimeMediaType(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.MediaType.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.MediaType.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.MediaType} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.MediaType.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeString(
-      3,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string codec_name = 1;
- * @return {string}
- */
-proto.MediaType.prototype.getCodecName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.setCodecName = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.clearCodecName = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.MediaType.prototype.hasCodecName = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string container = 2;
- * @return {string}
- */
-proto.MediaType.prototype.getContainer = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.setContainer = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.clearContainer = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.MediaType.prototype.hasContainer = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional string mime_media_type = 3;
- * @return {string}
- */
-proto.MediaType.prototype.getMimeMediaType = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.setMimeMediaType = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.MediaType} returns this
- */
-proto.MediaType.prototype.clearMimeMediaType = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.MediaType.prototype.hasMimeMediaType = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-
-/**
- * List of repeated fields within this message type.
- * @private {!Array<number>}
- * @const
- */
-proto.VideoMetadata.repeatedFields_ = [15];
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.VideoMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.VideoMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.VideoMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.VideoMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    title: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
-    description: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
-    video: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
-    thumbnailPhoto: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f,
-    duration: (f = jspb.Message.getField(msg, 5)) == null ? undefined : f,
-    mediaPixelHeight: (f = jspb.Message.getField(msg, 6)) == null ? undefined : f,
-    mediaPixelWidth: (f = jspb.Message.getField(msg, 7)) == null ? undefined : f,
-    mediaType: (f = msg.getMediaType()) && proto.MediaType.toObject(includeInstance, f),
-    language: (f = jspb.Message.getField(msg, 9)) == null ? undefined : f,
-    license: (f = msg.getLicense()) && proto.License.toObject(includeInstance, f),
-    publishedBeforeJoystream: (f = msg.getPublishedBeforeJoystream()) && proto.PublishedBeforeJoystream.toObject(includeInstance, f),
-    hasMarketing: (f = jspb.Message.getBooleanField(msg, 12)) == null ? undefined : f,
-    isPublic: (f = jspb.Message.getBooleanField(msg, 13)) == null ? undefined : f,
-    isExplicit: (f = jspb.Message.getBooleanField(msg, 14)) == null ? undefined : f,
-    personsList: (f = jspb.Message.getRepeatedField(msg, 15)) == null ? undefined : f,
-    category: (f = jspb.Message.getField(msg, 16)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.VideoMetadata}
- */
-proto.VideoMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.VideoMetadata;
-  return proto.VideoMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.VideoMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.VideoMetadata}
- */
-proto.VideoMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setTitle(value);
-      break;
-    case 2:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setDescription(value);
-      break;
-    case 3:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setVideo(value);
-      break;
-    case 4:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setThumbnailPhoto(value);
-      break;
-    case 5:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setDuration(value);
-      break;
-    case 6:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setMediaPixelHeight(value);
-      break;
-    case 7:
-      var value = /** @type {number} */ (reader.readUint32());
-      msg.setMediaPixelWidth(value);
-      break;
-    case 8:
-      var value = new proto.MediaType;
-      reader.readMessage(value,proto.MediaType.deserializeBinaryFromReader);
-      msg.setMediaType(value);
-      break;
-    case 9:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setLanguage(value);
-      break;
-    case 10:
-      var value = new proto.License;
-      reader.readMessage(value,proto.License.deserializeBinaryFromReader);
-      msg.setLicense(value);
-      break;
-    case 11:
-      var value = new proto.PublishedBeforeJoystream;
-      reader.readMessage(value,proto.PublishedBeforeJoystream.deserializeBinaryFromReader);
-      msg.setPublishedBeforeJoystream(value);
-      break;
-    case 12:
-      var value = /** @type {boolean} */ (reader.readBool());
-      msg.setHasMarketing(value);
-      break;
-    case 13:
-      var value = /** @type {boolean} */ (reader.readBool());
-      msg.setIsPublic(value);
-      break;
-    case 14:
-      var value = /** @type {boolean} */ (reader.readBool());
-      msg.setIsExplicit(value);
-      break;
-    case 15:
-      var values = /** @type {!Array<number>} */ (reader.isDelimited() ? reader.readPackedUint64() : [reader.readUint64()]);
-      for (var i = 0; i < values.length; i++) {
-        msg.addPersons(values[i]);
-      }
-      break;
-    case 16:
-      var value = /** @type {number} */ (reader.readUint64());
-      msg.setCategory(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.VideoMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.VideoMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.VideoMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.VideoMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 2));
-  if (f != null) {
-    writer.writeString(
-      2,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 3));
-  if (f != null) {
-    writer.writeUint32(
-      3,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 4));
-  if (f != null) {
-    writer.writeUint32(
-      4,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 5));
-  if (f != null) {
-    writer.writeUint32(
-      5,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 6));
-  if (f != null) {
-    writer.writeUint32(
-      6,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 7));
-  if (f != null) {
-    writer.writeUint32(
-      7,
-      f
-    );
-  }
-  f = message.getMediaType();
-  if (f != null) {
-    writer.writeMessage(
-      8,
-      f,
-      proto.MediaType.serializeBinaryToWriter
-    );
-  }
-  f = /** @type {string} */ (jspb.Message.getField(message, 9));
-  if (f != null) {
-    writer.writeString(
-      9,
-      f
-    );
-  }
-  f = message.getLicense();
-  if (f != null) {
-    writer.writeMessage(
-      10,
-      f,
-      proto.License.serializeBinaryToWriter
-    );
-  }
-  f = message.getPublishedBeforeJoystream();
-  if (f != null) {
-    writer.writeMessage(
-      11,
-      f,
-      proto.PublishedBeforeJoystream.serializeBinaryToWriter
-    );
-  }
-  f = /** @type {boolean} */ (jspb.Message.getField(message, 12));
-  if (f != null) {
-    writer.writeBool(
-      12,
-      f
-    );
-  }
-  f = /** @type {boolean} */ (jspb.Message.getField(message, 13));
-  if (f != null) {
-    writer.writeBool(
-      13,
-      f
-    );
-  }
-  f = /** @type {boolean} */ (jspb.Message.getField(message, 14));
-  if (f != null) {
-    writer.writeBool(
-      14,
-      f
-    );
-  }
-  f = message.getPersonsList();
-  if (f.length > 0) {
-    writer.writePackedUint64(
-      15,
-      f
-    );
-  }
-  f = /** @type {number} */ (jspb.Message.getField(message, 16));
-  if (f != null) {
-    writer.writeUint64(
-      16,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string title = 1;
- * @return {string}
- */
-proto.VideoMetadata.prototype.getTitle = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setTitle = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearTitle = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasTitle = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-/**
- * optional string description = 2;
- * @return {string}
- */
-proto.VideoMetadata.prototype.getDescription = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setDescription = function(value) {
-  return jspb.Message.setField(this, 2, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearDescription = function() {
-  return jspb.Message.setField(this, 2, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasDescription = function() {
-  return jspb.Message.getField(this, 2) != null;
-};
-
-
-/**
- * optional uint32 video = 3;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getVideo = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setVideo = function(value) {
-  return jspb.Message.setField(this, 3, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearVideo = function() {
-  return jspb.Message.setField(this, 3, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasVideo = function() {
-  return jspb.Message.getField(this, 3) != null;
-};
-
-
-/**
- * optional uint32 thumbnail_photo = 4;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getThumbnailPhoto = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setThumbnailPhoto = function(value) {
-  return jspb.Message.setField(this, 4, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearThumbnailPhoto = function() {
-  return jspb.Message.setField(this, 4, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasThumbnailPhoto = function() {
-  return jspb.Message.getField(this, 4) != null;
-};
-
-
-/**
- * optional uint32 duration = 5;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getDuration = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setDuration = function(value) {
-  return jspb.Message.setField(this, 5, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearDuration = function() {
-  return jspb.Message.setField(this, 5, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasDuration = function() {
-  return jspb.Message.getField(this, 5) != null;
-};
-
-
-/**
- * optional uint32 media_pixel_height = 6;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getMediaPixelHeight = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 6, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setMediaPixelHeight = function(value) {
-  return jspb.Message.setField(this, 6, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearMediaPixelHeight = function() {
-  return jspb.Message.setField(this, 6, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasMediaPixelHeight = function() {
-  return jspb.Message.getField(this, 6) != null;
-};
-
-
-/**
- * optional uint32 media_pixel_width = 7;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getMediaPixelWidth = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setMediaPixelWidth = function(value) {
-  return jspb.Message.setField(this, 7, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearMediaPixelWidth = function() {
-  return jspb.Message.setField(this, 7, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasMediaPixelWidth = function() {
-  return jspb.Message.getField(this, 7) != null;
-};
-
-
-/**
- * optional MediaType media_type = 8;
- * @return {?proto.MediaType}
- */
-proto.VideoMetadata.prototype.getMediaType = function() {
-  return /** @type{?proto.MediaType} */ (
-    jspb.Message.getWrapperField(this, proto.MediaType, 8));
-};
-
-
-/**
- * @param {?proto.MediaType|undefined} value
- * @return {!proto.VideoMetadata} returns this
-*/
-proto.VideoMetadata.prototype.setMediaType = function(value) {
-  return jspb.Message.setWrapperField(this, 8, value);
-};
-
-
-/**
- * Clears the message field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearMediaType = function() {
-  return this.setMediaType(undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasMediaType = function() {
-  return jspb.Message.getField(this, 8) != null;
-};
-
-
-/**
- * optional string language = 9;
- * @return {string}
- */
-proto.VideoMetadata.prototype.getLanguage = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 9, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setLanguage = function(value) {
-  return jspb.Message.setField(this, 9, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearLanguage = function() {
-  return jspb.Message.setField(this, 9, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasLanguage = function() {
-  return jspb.Message.getField(this, 9) != null;
-};
-
-
-/**
- * optional License license = 10;
- * @return {?proto.License}
- */
-proto.VideoMetadata.prototype.getLicense = function() {
-  return /** @type{?proto.License} */ (
-    jspb.Message.getWrapperField(this, proto.License, 10));
-};
-
-
-/**
- * @param {?proto.License|undefined} value
- * @return {!proto.VideoMetadata} returns this
-*/
-proto.VideoMetadata.prototype.setLicense = function(value) {
-  return jspb.Message.setWrapperField(this, 10, value);
-};
-
-
-/**
- * Clears the message field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearLicense = function() {
-  return this.setLicense(undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasLicense = function() {
-  return jspb.Message.getField(this, 10) != null;
-};
-
-
-/**
- * optional PublishedBeforeJoystream published_before_joystream = 11;
- * @return {?proto.PublishedBeforeJoystream}
- */
-proto.VideoMetadata.prototype.getPublishedBeforeJoystream = function() {
-  return /** @type{?proto.PublishedBeforeJoystream} */ (
-    jspb.Message.getWrapperField(this, proto.PublishedBeforeJoystream, 11));
-};
-
-
-/**
- * @param {?proto.PublishedBeforeJoystream|undefined} value
- * @return {!proto.VideoMetadata} returns this
-*/
-proto.VideoMetadata.prototype.setPublishedBeforeJoystream = function(value) {
-  return jspb.Message.setWrapperField(this, 11, value);
-};
-
-
-/**
- * Clears the message field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearPublishedBeforeJoystream = function() {
-  return this.setPublishedBeforeJoystream(undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasPublishedBeforeJoystream = function() {
-  return jspb.Message.getField(this, 11) != null;
-};
-
-
-/**
- * optional bool has_marketing = 12;
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.getHasMarketing = function() {
-  return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 12, false));
-};
-
-
-/**
- * @param {boolean} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setHasMarketing = function(value) {
-  return jspb.Message.setField(this, 12, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearHasMarketing = function() {
-  return jspb.Message.setField(this, 12, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasHasMarketing = function() {
-  return jspb.Message.getField(this, 12) != null;
-};
-
-
-/**
- * optional bool is_public = 13;
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.getIsPublic = function() {
-  return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 13, false));
-};
-
-
-/**
- * @param {boolean} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setIsPublic = function(value) {
-  return jspb.Message.setField(this, 13, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearIsPublic = function() {
-  return jspb.Message.setField(this, 13, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasIsPublic = function() {
-  return jspb.Message.getField(this, 13) != null;
-};
-
-
-/**
- * optional bool is_explicit = 14;
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.getIsExplicit = function() {
-  return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 14, false));
-};
-
-
-/**
- * @param {boolean} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setIsExplicit = function(value) {
-  return jspb.Message.setField(this, 14, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearIsExplicit = function() {
-  return jspb.Message.setField(this, 14, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasIsExplicit = function() {
-  return jspb.Message.getField(this, 14) != null;
-};
-
-
-/**
- * repeated uint64 persons = 15;
- * @return {!Array<number>}
- */
-proto.VideoMetadata.prototype.getPersonsList = function() {
-  return /** @type {!Array<number>} */ (jspb.Message.getRepeatedField(this, 15));
-};
-
-
-/**
- * @param {!Array<number>} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setPersonsList = function(value) {
-  return jspb.Message.setField(this, 15, value || []);
-};
-
-
-/**
- * @param {number} value
- * @param {number=} opt_index
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.addPersons = function(value, opt_index) {
-  return jspb.Message.addToRepeatedField(this, 15, value, opt_index);
-};
-
-
-/**
- * Clears the list making it empty but non-null.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearPersonsList = function() {
-  return this.setPersonsList([]);
-};
-
-
-/**
- * optional uint64 category = 16;
- * @return {number}
- */
-proto.VideoMetadata.prototype.getCategory = function() {
-  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 16, 0));
-};
-
-
-/**
- * @param {number} value
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.setCategory = function(value) {
-  return jspb.Message.setField(this, 16, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoMetadata} returns this
- */
-proto.VideoMetadata.prototype.clearCategory = function() {
-  return jspb.Message.setField(this, 16, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoMetadata.prototype.hasCategory = function() {
-  return jspb.Message.getField(this, 16) != null;
-};
-
-
-
-
-
-if (jspb.Message.GENERATE_TO_OBJECT) {
-/**
- * Creates an object representation of this proto.
- * Field names that are reserved in JavaScript and will be renamed to pb_name.
- * Optional fields that are not set will be set to undefined.
- * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
- * For the list of reserved names please see:
- *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
- * @param {boolean=} opt_includeInstance Deprecated. whether to include the
- *     JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @return {!Object}
- */
-proto.VideoCategoryMetadata.prototype.toObject = function(opt_includeInstance) {
-  return proto.VideoCategoryMetadata.toObject(opt_includeInstance, this);
-};
-
-
-/**
- * Static version of the {@see toObject} method.
- * @param {boolean|undefined} includeInstance Deprecated. Whether to include
- *     the JSPB instance for transitional soy proto support:
- *     http://goto/soy-param-migration
- * @param {!proto.VideoCategoryMetadata} msg The msg instance to transform.
- * @return {!Object}
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.VideoCategoryMetadata.toObject = function(includeInstance, msg) {
-  var f, obj = {
-    name: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f
-  };
-
-  if (includeInstance) {
-    obj.$jspbMessageInstance = msg;
-  }
-  return obj;
-};
-}
-
-
-/**
- * Deserializes binary data (in protobuf wire format).
- * @param {jspb.ByteSource} bytes The bytes to deserialize.
- * @return {!proto.VideoCategoryMetadata}
- */
-proto.VideoCategoryMetadata.deserializeBinary = function(bytes) {
-  var reader = new jspb.BinaryReader(bytes);
-  var msg = new proto.VideoCategoryMetadata;
-  return proto.VideoCategoryMetadata.deserializeBinaryFromReader(msg, reader);
-};
-
-
-/**
- * Deserializes binary data (in protobuf wire format) from the
- * given reader into the given message object.
- * @param {!proto.VideoCategoryMetadata} msg The message object to deserialize into.
- * @param {!jspb.BinaryReader} reader The BinaryReader to use.
- * @return {!proto.VideoCategoryMetadata}
- */
-proto.VideoCategoryMetadata.deserializeBinaryFromReader = function(msg, reader) {
-  while (reader.nextField()) {
-    if (reader.isEndGroup()) {
-      break;
-    }
-    var field = reader.getFieldNumber();
-    switch (field) {
-    case 1:
-      var value = /** @type {string} */ (reader.readString());
-      msg.setName(value);
-      break;
-    default:
-      reader.skipField();
-      break;
-    }
-  }
-  return msg;
-};
-
-
-/**
- * Serializes the message to binary data (in protobuf wire format).
- * @return {!Uint8Array}
- */
-proto.VideoCategoryMetadata.prototype.serializeBinary = function() {
-  var writer = new jspb.BinaryWriter();
-  proto.VideoCategoryMetadata.serializeBinaryToWriter(this, writer);
-  return writer.getResultBuffer();
-};
-
-
-/**
- * Serializes the given message to binary data (in protobuf wire
- * format), writing to the given BinaryWriter.
- * @param {!proto.VideoCategoryMetadata} message
- * @param {!jspb.BinaryWriter} writer
- * @suppress {unusedLocalVariables} f is only used for nested messages
- */
-proto.VideoCategoryMetadata.serializeBinaryToWriter = function(message, writer) {
-  var f = undefined;
-  f = /** @type {string} */ (jspb.Message.getField(message, 1));
-  if (f != null) {
-    writer.writeString(
-      1,
-      f
-    );
-  }
-};
-
-
-/**
- * optional string name = 1;
- * @return {string}
- */
-proto.VideoCategoryMetadata.prototype.getName = function() {
-  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
-};
-
-
-/**
- * @param {string} value
- * @return {!proto.VideoCategoryMetadata} returns this
- */
-proto.VideoCategoryMetadata.prototype.setName = function(value) {
-  return jspb.Message.setField(this, 1, value);
-};
-
-
-/**
- * Clears the field making it undefined.
- * @return {!proto.VideoCategoryMetadata} returns this
- */
-proto.VideoCategoryMetadata.prototype.clearName = function() {
-  return jspb.Message.setField(this, 1, undefined);
-};
-
-
-/**
- * Returns whether this field is set.
- * @return {boolean}
- */
-proto.VideoCategoryMetadata.prototype.hasName = function() {
-  return jspb.Message.getField(this, 1) != null;
-};
-
-
-goog.object.extend(exports, proto);

+ 0 - 374
content-metadata-protobuf/doc/index.md

@@ -1,374 +0,0 @@
-# Protocol Documentation
-<a name="top"></a>
-
-## Table of Contents
-
-- [proto/Channel.proto](#proto/Channel.proto)
-    - [ChannelCategoryMetadata](#.ChannelCategoryMetadata)
-    - [ChannelMetadata](#.ChannelMetadata)
-  
-- [proto/Person.proto](#proto/Person.proto)
-    - [PersonMetadata](#.PersonMetadata)
-  
-- [proto/Playlist.proto](#proto/Playlist.proto)
-    - [PlaylistMetadata](#.PlaylistMetadata)
-  
-- [proto/Series.proto](#proto/Series.proto)
-    - [SeasonMetadata](#.SeasonMetadata)
-    - [SeriesMetadata](#.SeriesMetadata)
-  
-- [proto/Video.proto](#proto/Video.proto)
-    - [License](#.License)
-    - [MediaType](#.MediaType)
-    - [PublishedBeforeJoystream](#.PublishedBeforeJoystream)
-    - [VideoCategoryMetadata](#.VideoCategoryMetadata)
-    - [VideoMetadata](#.VideoMetadata)
-  
-- [Scalar Value Types](#scalar-value-types)
-
-
-
-<a name="proto/Channel.proto"></a>
-<p align="right"><a href="#top">Top</a></p>
-
-## proto/Channel.proto
-
-
-
-<a name=".ChannelCategoryMetadata"></a>
-
-### ChannelCategoryMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| name | [string](#string) | optional | Category Name |
-
-
-
-
-
-
-<a name=".ChannelMetadata"></a>
-
-### ChannelMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| title | [string](#string) | optional | Channel Title |
-| description | [string](#string) | optional | Channel Description |
-| is_public | [bool](#bool) | optional | Wether to display channel to the public |
-| language | [string](#string) | optional | ISO_639-1 Language [Code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) |
-| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| avatar_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| category | [uint64](#uint64) | optional | Channel Category Id |
-
-
-
-
-
- 
-
- 
-
- 
-
- 
-
-
-
-<a name="proto/Person.proto"></a>
-<p align="right"><a href="#top">Top</a></p>
-
-## proto/Person.proto
-
-
-
-<a name=".PersonMetadata"></a>
-
-### PersonMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| first_name | [string](#string) | optional |  |
-| middle_name | [string](#string) | optional |  |
-| last_name | [string](#string) | optional |  |
-| about | [string](#string) | optional |  |
-| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| avatar_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-
-
-
-
-
- 
-
- 
-
- 
-
- 
-
-
-
-<a name="proto/Playlist.proto"></a>
-<p align="right"><a href="#top">Top</a></p>
-
-## proto/Playlist.proto
-
-
-
-<a name=".PlaylistMetadata"></a>
-
-### PlaylistMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| title | [string](#string) | optional |  |
-| videos | [uint64](#uint64) | repeated | Videos in the playlist |
-
-
-
-
-
- 
-
- 
-
- 
-
- 
-
-
-
-<a name="proto/Series.proto"></a>
-<p align="right"><a href="#top">Top</a></p>
-
-## proto/Series.proto
-
-
-
-<a name=".SeasonMetadata"></a>
-
-### SeasonMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| title | [string](#string) | optional |  |
-| description | [string](#string) | optional |  |
-| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this Season |
-
-
-
-
-
-
-<a name=".SeriesMetadata"></a>
-
-### SeriesMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| title | [string](#string) | optional |  |
-| description | [string](#string) | optional |  |
-| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this Series |
-
-
-
-
-
- 
-
- 
-
- 
-
- 
-
-
-
-<a name="proto/Video.proto"></a>
-<p align="right"><a href="#top">Top</a></p>
-
-## proto/Video.proto
-
-
-
-<a name=".License"></a>
-
-### License
-License types defined by Joystream
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| code | [uint32](#uint32) | optional | License code defined by Joystream. [reference](../src/KnownLicenses.json) |
-| attribution | [string](#string) | optional | Text for licenses that require an attribution |
-| custom_text | [string](#string) | optional | Text for custom license type |
-
-
-
-
-
-
-<a name=".MediaType"></a>
-
-### MediaType
-Codec, Container, MIME media-type information
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| codec_name | [string](#string) | optional | Codec corresponding to `name` field from [FFmpeg](https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/codec_desc.c) |
-| container | [string](#string) | optional | Video container format, eg. &#39;MP4&#39;, &#39;WebM&#39;, &#39;Ogg&#39; [ref](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs) |
-| mime_media_type | [string](#string) | optional | MIME Media Type, eg. &#39;video/mp4&#39; [ref](https://www.iana.org/assignments/media-types/media-types.xhtml#video) |
-
-
-
-
-
-
-<a name=".PublishedBeforeJoystream"></a>
-
-### PublishedBeforeJoystream
-Publication status before joystream
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| is_published | [bool](#bool) | optional | Was video published before joystream platform |
-| date | [string](#string) | optional | Date of publication: &#39;YYYY-MM-DD&#39; [ISO-8601](https://www.iso.org/iso-8601-date-and-time-format.html) |
-
-
-
-
-
-
-<a name=".VideoCategoryMetadata"></a>
-
-### VideoCategoryMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| name | [string](#string) | optional | Category name |
-
-
-
-
-
-
-<a name=".VideoMetadata"></a>
-
-### VideoMetadata
-
-
-
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| title | [string](#string) | optional | Video Title |
-| description | [string](#string) | optional | Video Description |
-| video | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| thumbnail_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
-| duration | [uint32](#uint32) | optional | Lengths of video in seconds |
-| media_pixel_height | [uint32](#uint32) | optional | Resolution of the video (Height) |
-| media_pixel_width | [uint32](#uint32) | optional | Resolution of the video (Width) |
-| media_type | [MediaType](#MediaType) | optional | Encoding and Container format used |
-| language | [string](#string) | optional | ISO_639-1 Language [Code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) |
-| license | [License](#License) | optional | License type for the media |
-| published_before_joystream | [PublishedBeforeJoystream](#PublishedBeforeJoystream) | optional | Date of publication |
-| has_marketing | [bool](#bool) | optional | Does video have marketing or advertising in the stream |
-| is_public | [bool](#bool) | optional | Should video be publicy visible yet |
-| is_explicit | [bool](#bool) | optional | Does Video have explicit language or scenes |
-| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this video |
-| category | [uint64](#uint64) | optional | Video Category Id |
-
-
-
-
-
- 
-
- 
-
- 
-
- 
-
-
-
-## Scalar Value Types
-
-| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
-| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |
-| <a name="double" /> double |  | double | double | float | float64 | double | float | Float |
-| <a name="float" /> float |  | float | float | float | float32 | float | float | Float |
-| <a name="int32" /> int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| <a name="int64" /> int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| <a name="uint32" /> uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
-| <a name="uint64" /> uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
-| <a name="sint32" /> sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| <a name="sint64" /> sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| <a name="fixed32" /> fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
-| <a name="fixed64" /> fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
-| <a name="sfixed32" /> sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
-| <a name="sfixed64" /> sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
-| <a name="bool" /> bool |  | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |
-| <a name="string" /> string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
-| <a name="bytes" /> bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
-
-<!-- 
-    This extra documentation will be appended to the generated docs.
--->
-
-## Referencing Assets
-<a name=".Assets"></a>
-
-Applications that process messages that contain a `uint32` field that references an asset such as a cover photo or video, should interpret this value as a zero based index into an array/vector that is received external (out of band) to the protobuf message.
-
-Example in context of query-node processing the runtime event `VideoCreated`
-
-```rust
-// Runtime event associated with creating a Video
-VideoCreated(video_id: VideoId, video: Video, assets: Vec<NewAsset>, params: VideoCreationParameters)
-
-struct VideoCreationParameters {
-  in_category: VideoCategoryId,
-  // binary serialized VideoMetadata protobuf message
-  meta: Vec<u8>,
-}
-
-// suppose assets is a vector of two elements. This is the "out of band" array being referenced by the VideoMetadata message
-assets = [
-    NewAsset::Uri("https://mydomain.net/thumbnail.png"),
-    NewAsset::Upload({
-       content_id,
-       ipfs_hash,
-       size,
-       ...
-    }),
-];
-
-meta = VideoMetadata {
-    ...
-    // refers to second element: assets[1] which is being uploaded to the storage system
-    video: 1,
-    // refers to the first element assets[0] which is being referneced by a url string.
-    thumbnail_photo: 0,
-    ...
-};
-```

+ 0 - 13
content-metadata-protobuf/generate-md-doc.sh

@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-
-# Directory to write generated documentation to
-OUT_DIR_DOC="./doc"
-mkdir -p ${OUT_DIR_DOC}
-
-# Gernerate Markdown docs
-protoc \
-    --doc_out="${OUT_DIR_DOC}" --doc_opt=markdown,index.md \
-    proto/*.proto
-
-# Append some custom docs to generated protocol docs
-cat doc-appendix.md >> ${OUT_DIR_DOC}/index.md

+ 0 - 47
content-metadata-protobuf/package.json

@@ -1,47 +0,0 @@
-{
-  "name": "@joystream/content-metadata-protobuf",
-  "version": "1.1.0",
-  "description": "Joystream Content Metadata Protobuf Library ",
-  "main": "lib/index.js",
-  "types": "lib/index.d.ts",
-  "repository": "https://github.com/joystream/joystream",
-  "author": "Joystream Contributors",
-  "license": "MIT",
-  "private": false,
-  "scripts": {
-    "build": "./compile.sh && yarn build:ts",
-    "build:ts": "tsc",
-    "compile": "./compile.sh",
-    "generate-doc": "./generate-md-doc.sh",
-    "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register 'test/**/*.ts'",
-    "lint": "eslint ./src --ext .ts",
-    "checks": "tsc --noEmit --pretty && prettier ./ --check && yarn lint",
-    "format": "prettier ./ --write",
-    "prepublish": "yarn build"
-  },
-  "files": [
-    "lib/**/*",
-    "doc/**",
-    "proto/**",
-    "compiled/**/*",
-    "README.md"
-  ],
-  "dependencies": {
-    "google-protobuf": "^3.14.0"
-  },
-  "devDependencies": {
-    "@types/chai": "^4.2.11",
-    "@types/mocha": "^8.2.0",
-    "chai": "^4.2.0",
-    "eslint": "^7.6.0",
-    "mocha": "^8.2.1",
-    "prettier": "2.0.2",
-    "ts-node": "^8.8.1",
-    "ts-protoc-gen": "^0.14.0",
-    "typescript": "^4.1.3"
-  },
-  "publishConfig": {
-    "access": "public",
-    "registry": "https://registry.npmjs.org"
-  }
-}

+ 0 - 10
content-metadata-protobuf/src/index.ts

@@ -1,10 +0,0 @@
-// Some helpers for constructing known licenses
-import licenses from './licenses'
-export { licenses }
-
-// protobuf message constructors
-export * from '../compiled/proto/Video_pb'
-export * from '../compiled/proto/Channel_pb'
-export * from '../compiled/proto/Person_pb'
-export * from '../compiled/proto/Playlist_pb'
-export * from '../compiled/proto/Series_pb'

+ 0 - 33
content-metadata-protobuf/test/channel.ts

@@ -1,33 +0,0 @@
-import { ChannelMetadata } from '../src'
-import { assert } from 'chai'
-
-describe('Channel Metadata', () => {
-  it('Message', () => {
-    const channel = new ChannelMetadata()
-
-    const title = 'title'
-    const description = 'description'
-    const isPublic = false
-    const language = 'fr'
-
-    channel.setTitle(title)
-    channel.setDescription(description)
-    channel.setIsPublic(isPublic)
-    channel.setLanguage(language)
-    channel.setAvatarPhoto(0)
-    channel.setCoverPhoto(1)
-    channel.setCategory(100)
-
-    assert.deepEqual(channel.toObject(), {
-      title,
-      description,
-      isPublic,
-      language,
-      avatarPhoto: 0,
-      coverPhoto: 1,
-      category: 100,
-    })
-
-    assert.deepEqual(ChannelMetadata.deserializeBinary(channel.serializeBinary()), channel)
-  })
-})

+ 0 - 115
content-metadata-protobuf/test/video.ts

@@ -1,115 +0,0 @@
-import { VideoMetadata, PublishedBeforeJoystream, MediaType, License } from '../src'
-import { assert, expect } from 'chai'
-
-describe('Video Metadata', () => {
-  it('Message', () => {
-    const meta = new VideoMetadata()
-
-    const title = 'Video Title'
-    const description = 'Video Description'
-    const duration = 100
-
-    meta.setTitle(title)
-    meta.setDescription(description)
-    meta.setDuration(duration)
-    meta.setMediaPixelHeight(1)
-    meta.setMediaPixelWidth(2)
-    meta.setMediaType(new MediaType())
-    meta.setLanguage('en')
-    meta.setLicense(new License())
-    meta.setPublishedBeforeJoystream(new PublishedBeforeJoystream())
-    meta.setHasMarketing(true)
-    meta.setIsPublic(true)
-    meta.setIsExplicit(false)
-    meta.setVideo(0)
-    meta.setThumbnailPhoto(1)
-    meta.setCategory(101)
-
-    assert.deepEqual(meta.toObject(), {
-      title,
-      description,
-      duration,
-      mediaPixelHeight: 1,
-      mediaPixelWidth: 2,
-      mediaType: {
-        codecName: undefined,
-        container: undefined,
-        mimeMediaType: undefined,
-      },
-      language: 'en',
-      license: {
-        code: undefined,
-        attribution: undefined,
-        customText: undefined,
-      },
-      publishedBeforeJoystream: { isPublished: undefined, date: undefined },
-      hasMarketing: true,
-      isPublic: true,
-      isExplicit: false,
-      thumbnailPhoto: 1,
-      video: 0,
-      personsList: [],
-      category: 101,
-    })
-
-    // sanity check - encoding / decoding works
-    assert.deepEqual(VideoMetadata.deserializeBinary(meta.serializeBinary()), meta)
-  })
-
-  it('Message: PublishedBeforeJoystream', () => {
-    const meta = new VideoMetadata()
-
-    expect(meta.hasPublishedBeforeJoystream()).equals(false, 'PublishedBeforeJoystream field should NOT be set')
-
-    const published = new PublishedBeforeJoystream()
-    const isPublished = true
-    const date = '1950-12-24'
-    published.setIsPublished(isPublished)
-    published.setDate(date)
-
-    meta.setPublishedBeforeJoystream(published)
-
-    // Field should now be set
-    expect(meta.hasPublishedBeforeJoystream()).equals(true, 'PublishedBeforeJoystream field should be set')
-
-    assert.deepEqual(published.toObject(), {
-      isPublished,
-      date,
-    })
-  })
-
-  it('Message: License', () => {
-    const license = new License()
-
-    const code = 1000
-    const attribution = 'Attribution Text'
-    const customText = 'Custom License Details'
-    license.setCode(code)
-    license.setAttribution(attribution)
-    license.setCustomText(customText)
-
-    assert.deepEqual(license.toObject(), {
-      code,
-      attribution,
-      customText,
-    })
-  })
-
-  it('Message: MediaType', () => {
-    const mediaType = new MediaType()
-
-    const codecName = 'mpeg4'
-    const container = 'avi'
-    const mimeMediaType = 'videp/mp4'
-
-    mediaType.setCodecName(codecName)
-    mediaType.setContainer(container)
-    mediaType.setMimeMediaType(mimeMediaType)
-
-    assert.deepEqual(mediaType.toObject(), {
-      codecName,
-      container,
-      mimeMediaType,
-    })
-  })
-})

+ 0 - 15
content-metadata-protobuf/tsconfig.json

@@ -1,15 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "esnext",
-    "module": "commonjs",
-    "outDir": "lib",
-    "strict": true,
-    "declaration": true,
-    "esModuleInterop": true,
-    "forceConsistentCasingInFileNames": true,
-    "skipLibCheck": true,
-    "resolveJsonModule": true,
-  },
-  "include": ["src"],
-  "exclude": ["node_modules", "test"]
-}

+ 1 - 0
metadata-protobuf/.gitignore

@@ -1,2 +1,3 @@
 node_modules/
 lib/
+compiled/

+ 5 - 7
metadata-protobuf/README.md

@@ -1,6 +1,6 @@
-## Joystream Content Directory Metadata Library
+## Joystream Metadata Library
 
-This package contains protobuf message definitions compiled to Javascript/Typescript used for creating and updating various metadata blobs in the joystream content directory.
+This package contains protobuf message definitions compiled to Javascript/Typescript used for creating and updating various metadata blobs in Joystream.
 
 ### Message Specs
 
@@ -27,12 +27,10 @@ useful npm package https://www.npmjs.com/package/iso-639-1
 
 ### Building the package
 
-Building will compile the protofiles and build the library from source.
-
-- pre-requisists for compiling protofiles:
-    - [protoc](https://github.com/protocolbuffers/protobuf/releases)
+Building will compile the protofiles using [protobufjs](https://www.npmjs.com/package/protobufjs) and build the library from source.
 
 - pre-requisists for generating documentation:
+    - [protoc](https://github.com/protocolbuffers/protobuf/releases)
     - [golang](https://golang.org/)
     - [protoc-gen-doc](https://github.com/pseudomuto/protoc-gen-doc) to generate docs
 
@@ -50,4 +48,4 @@ yarn generate-docs
 
 ```
 yarn test
-```
+```

+ 1421 - 203
metadata-protobuf/compiled/index.d.ts

@@ -1,504 +1,1722 @@
 import { Long } from 'long'
 import * as $protobuf from "protobufjs";
+/** Properties of a ChannelMetadata. */
+export interface IChannelMetadata {
+
+    /** ChannelMetadata title */
+    title?: (string|null);
+
+    /** ChannelMetadata description */
+    description?: (string|null);
+
+    /** ChannelMetadata isPublic */
+    isPublic?: (boolean|null);
+
+    /** ChannelMetadata language */
+    language?: (string|null);
+
+    /** ChannelMetadata coverPhoto */
+    coverPhoto?: (number|null);
+
+    /** ChannelMetadata avatarPhoto */
+    avatarPhoto?: (number|null);
+
+    /** ChannelMetadata category */
+    category?: (Long|null);
+}
+
+/** Represents a ChannelMetadata. */
+export class ChannelMetadata implements IChannelMetadata {
+
+    /**
+     * Constructs a new ChannelMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IChannelMetadata);
+
+    /** ChannelMetadata title. */
+    public title: string;
+
+    /** ChannelMetadata description. */
+    public description: string;
+
+    /** ChannelMetadata isPublic. */
+    public isPublic: boolean;
+
+    /** ChannelMetadata language. */
+    public language: string;
+
+    /** ChannelMetadata coverPhoto. */
+    public coverPhoto: number;
+
+    /** ChannelMetadata avatarPhoto. */
+    public avatarPhoto: number;
+
+    /** ChannelMetadata category. */
+    public category: Long;
+
+    /**
+     * Creates a new ChannelMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns ChannelMetadata instance
+     */
+    public static create(properties?: IChannelMetadata): ChannelMetadata;
+
+    /**
+     * Encodes the specified ChannelMetadata message. Does not implicitly {@link ChannelMetadata.verify|verify} messages.
+     * @param message ChannelMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IChannelMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified ChannelMetadata message, length delimited. Does not implicitly {@link ChannelMetadata.verify|verify} messages.
+     * @param message ChannelMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IChannelMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a ChannelMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns ChannelMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): ChannelMetadata;
+
+    /**
+     * Decodes a ChannelMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns ChannelMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): ChannelMetadata;
+
+    /**
+     * Verifies a ChannelMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a ChannelMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns ChannelMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): ChannelMetadata;
+
+    /**
+     * Creates a plain object from a ChannelMetadata message. Also converts values to other types if specified.
+     * @param message ChannelMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: ChannelMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this ChannelMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a ChannelCategoryMetadata. */
+export interface IChannelCategoryMetadata {
+
+    /** ChannelCategoryMetadata name */
+    name?: (string|null);
+}
+
+/** Represents a ChannelCategoryMetadata. */
+export class ChannelCategoryMetadata implements IChannelCategoryMetadata {
+
+    /**
+     * Constructs a new ChannelCategoryMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IChannelCategoryMetadata);
+
+    /** ChannelCategoryMetadata name. */
+    public name: string;
+
+    /**
+     * Creates a new ChannelCategoryMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns ChannelCategoryMetadata instance
+     */
+    public static create(properties?: IChannelCategoryMetadata): ChannelCategoryMetadata;
+
+    /**
+     * Encodes the specified ChannelCategoryMetadata message. Does not implicitly {@link ChannelCategoryMetadata.verify|verify} messages.
+     * @param message ChannelCategoryMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IChannelCategoryMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified ChannelCategoryMetadata message, length delimited. Does not implicitly {@link ChannelCategoryMetadata.verify|verify} messages.
+     * @param message ChannelCategoryMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IChannelCategoryMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a ChannelCategoryMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns ChannelCategoryMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): ChannelCategoryMetadata;
+
+    /**
+     * Decodes a ChannelCategoryMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns ChannelCategoryMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): ChannelCategoryMetadata;
+
+    /**
+     * Verifies a ChannelCategoryMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a ChannelCategoryMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns ChannelCategoryMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): ChannelCategoryMetadata;
+
+    /**
+     * Creates a plain object from a ChannelCategoryMetadata message. Also converts values to other types if specified.
+     * @param message ChannelCategoryMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: ChannelCategoryMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this ChannelCategoryMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a PersonMetadata. */
+export interface IPersonMetadata {
+
+    /** PersonMetadata firstName */
+    firstName?: (string|null);
+
+    /** PersonMetadata middleName */
+    middleName?: (string|null);
+
+    /** PersonMetadata lastName */
+    lastName?: (string|null);
+
+    /** PersonMetadata about */
+    about?: (string|null);
+
+    /** PersonMetadata coverPhoto */
+    coverPhoto?: (number|null);
+
+    /** PersonMetadata avatarPhoto */
+    avatarPhoto?: (number|null);
+}
+
+/** Represents a PersonMetadata. */
+export class PersonMetadata implements IPersonMetadata {
+
+    /**
+     * Constructs a new PersonMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IPersonMetadata);
+
+    /** PersonMetadata firstName. */
+    public firstName: string;
+
+    /** PersonMetadata middleName. */
+    public middleName: string;
+
+    /** PersonMetadata lastName. */
+    public lastName: string;
+
+    /** PersonMetadata about. */
+    public about: string;
+
+    /** PersonMetadata coverPhoto. */
+    public coverPhoto: number;
+
+    /** PersonMetadata avatarPhoto. */
+    public avatarPhoto: number;
+
+    /**
+     * Creates a new PersonMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns PersonMetadata instance
+     */
+    public static create(properties?: IPersonMetadata): PersonMetadata;
+
+    /**
+     * Encodes the specified PersonMetadata message. Does not implicitly {@link PersonMetadata.verify|verify} messages.
+     * @param message PersonMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IPersonMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified PersonMetadata message, length delimited. Does not implicitly {@link PersonMetadata.verify|verify} messages.
+     * @param message PersonMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IPersonMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a PersonMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns PersonMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): PersonMetadata;
+
+    /**
+     * Decodes a PersonMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns PersonMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): PersonMetadata;
+
+    /**
+     * Verifies a PersonMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a PersonMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns PersonMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): PersonMetadata;
+
+    /**
+     * Creates a plain object from a PersonMetadata message. Also converts values to other types if specified.
+     * @param message PersonMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: PersonMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this PersonMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a PlaylistMetadata. */
+export interface IPlaylistMetadata {
+
+    /** PlaylistMetadata title */
+    title?: (string|null);
+
+    /** PlaylistMetadata videos */
+    videos?: (Long[]|null);
+}
+
+/** Represents a PlaylistMetadata. */
+export class PlaylistMetadata implements IPlaylistMetadata {
+
+    /**
+     * Constructs a new PlaylistMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IPlaylistMetadata);
+
+    /** PlaylistMetadata title. */
+    public title: string;
+
+    /** PlaylistMetadata videos. */
+    public videos: Long[];
+
+    /**
+     * Creates a new PlaylistMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns PlaylistMetadata instance
+     */
+    public static create(properties?: IPlaylistMetadata): PlaylistMetadata;
+
+    /**
+     * Encodes the specified PlaylistMetadata message. Does not implicitly {@link PlaylistMetadata.verify|verify} messages.
+     * @param message PlaylistMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IPlaylistMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified PlaylistMetadata message, length delimited. Does not implicitly {@link PlaylistMetadata.verify|verify} messages.
+     * @param message PlaylistMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IPlaylistMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a PlaylistMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns PlaylistMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): PlaylistMetadata;
+
+    /**
+     * Decodes a PlaylistMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns PlaylistMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): PlaylistMetadata;
+
+    /**
+     * Verifies a PlaylistMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a PlaylistMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns PlaylistMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): PlaylistMetadata;
+
+    /**
+     * Creates a plain object from a PlaylistMetadata message. Also converts values to other types if specified.
+     * @param message PlaylistMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: PlaylistMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this PlaylistMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a SeriesMetadata. */
+export interface ISeriesMetadata {
+
+    /** SeriesMetadata title */
+    title?: (string|null);
+
+    /** SeriesMetadata description */
+    description?: (string|null);
+
+    /** SeriesMetadata coverPhoto */
+    coverPhoto?: (number|null);
+
+    /** SeriesMetadata persons */
+    persons?: (Long[]|null);
+}
+
+/** Represents a SeriesMetadata. */
+export class SeriesMetadata implements ISeriesMetadata {
+
+    /**
+     * Constructs a new SeriesMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: ISeriesMetadata);
+
+    /** SeriesMetadata title. */
+    public title: string;
+
+    /** SeriesMetadata description. */
+    public description: string;
+
+    /** SeriesMetadata coverPhoto. */
+    public coverPhoto: number;
+
+    /** SeriesMetadata persons. */
+    public persons: Long[];
+
+    /**
+     * Creates a new SeriesMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns SeriesMetadata instance
+     */
+    public static create(properties?: ISeriesMetadata): SeriesMetadata;
+
+    /**
+     * Encodes the specified SeriesMetadata message. Does not implicitly {@link SeriesMetadata.verify|verify} messages.
+     * @param message SeriesMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: ISeriesMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified SeriesMetadata message, length delimited. Does not implicitly {@link SeriesMetadata.verify|verify} messages.
+     * @param message SeriesMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: ISeriesMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a SeriesMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns SeriesMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): SeriesMetadata;
+
+    /**
+     * Decodes a SeriesMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns SeriesMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): SeriesMetadata;
+
+    /**
+     * Verifies a SeriesMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a SeriesMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns SeriesMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): SeriesMetadata;
+
+    /**
+     * Creates a plain object from a SeriesMetadata message. Also converts values to other types if specified.
+     * @param message SeriesMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: SeriesMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this SeriesMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a SeasonMetadata. */
+export interface ISeasonMetadata {
+
+    /** SeasonMetadata title */
+    title?: (string|null);
+
+    /** SeasonMetadata description */
+    description?: (string|null);
+
+    /** SeasonMetadata coverPhoto */
+    coverPhoto?: (number|null);
+
+    /** SeasonMetadata persons */
+    persons?: (Long[]|null);
+}
+
+/** Represents a SeasonMetadata. */
+export class SeasonMetadata implements ISeasonMetadata {
+
+    /**
+     * Constructs a new SeasonMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: ISeasonMetadata);
+
+    /** SeasonMetadata title. */
+    public title: string;
+
+    /** SeasonMetadata description. */
+    public description: string;
+
+    /** SeasonMetadata coverPhoto. */
+    public coverPhoto: number;
+
+    /** SeasonMetadata persons. */
+    public persons: Long[];
+
+    /**
+     * Creates a new SeasonMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns SeasonMetadata instance
+     */
+    public static create(properties?: ISeasonMetadata): SeasonMetadata;
+
+    /**
+     * Encodes the specified SeasonMetadata message. Does not implicitly {@link SeasonMetadata.verify|verify} messages.
+     * @param message SeasonMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: ISeasonMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified SeasonMetadata message, length delimited. Does not implicitly {@link SeasonMetadata.verify|verify} messages.
+     * @param message SeasonMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: ISeasonMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a SeasonMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns SeasonMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): SeasonMetadata;
+
+    /**
+     * Decodes a SeasonMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns SeasonMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): SeasonMetadata;
+
+    /**
+     * Verifies a SeasonMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a SeasonMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns SeasonMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): SeasonMetadata;
+
+    /**
+     * Creates a plain object from a SeasonMetadata message. Also converts values to other types if specified.
+     * @param message SeasonMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: SeasonMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this SeasonMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
 /** Properties of a GeoCoordiantes. */
 export interface IGeoCoordiantes {
 
-    /** GeoCoordiantes latitude */
-    latitude?: (number|null);
+    /** GeoCoordiantes latitude */
+    latitude?: (number|null);
+
+    /** GeoCoordiantes longitude */
+    longitude?: (number|null);
+}
+
+/** Represents a GeoCoordiantes. */
+export class GeoCoordiantes implements IGeoCoordiantes {
+
+    /**
+     * Constructs a new GeoCoordiantes.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IGeoCoordiantes);
+
+    /** GeoCoordiantes latitude. */
+    public latitude: number;
+
+    /** GeoCoordiantes longitude. */
+    public longitude: number;
+
+    /**
+     * Creates a new GeoCoordiantes instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns GeoCoordiantes instance
+     */
+    public static create(properties?: IGeoCoordiantes): GeoCoordiantes;
+
+    /**
+     * Encodes the specified GeoCoordiantes message. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @param message GeoCoordiantes message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified GeoCoordiantes message, length delimited. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @param message GeoCoordiantes message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): GeoCoordiantes;
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): GeoCoordiantes;
+
+    /**
+     * Verifies a GeoCoordiantes message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a GeoCoordiantes message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns GeoCoordiantes
+     */
+    public static fromObject(object: { [k: string]: any }): GeoCoordiantes;
+
+    /**
+     * Creates a plain object from a GeoCoordiantes message. Also converts values to other types if specified.
+     * @param message GeoCoordiantes
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: GeoCoordiantes, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this GeoCoordiantes to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a NodeLocationMetadata. */
+export interface INodeLocationMetadata {
+
+    /** NodeLocationMetadata countryCode */
+    countryCode?: (string|null);
+
+    /** NodeLocationMetadata city */
+    city?: (string|null);
+
+    /** NodeLocationMetadata coordinates */
+    coordinates?: (IGeoCoordiantes|null);
+}
+
+/** Represents a NodeLocationMetadata. */
+export class NodeLocationMetadata implements INodeLocationMetadata {
+
+    /**
+     * Constructs a new NodeLocationMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: INodeLocationMetadata);
+
+    /** NodeLocationMetadata countryCode. */
+    public countryCode: string;
+
+    /** NodeLocationMetadata city. */
+    public city: string;
+
+    /** NodeLocationMetadata coordinates. */
+    public coordinates?: (IGeoCoordiantes|null);
+
+    /**
+     * Creates a new NodeLocationMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns NodeLocationMetadata instance
+     */
+    public static create(properties?: INodeLocationMetadata): NodeLocationMetadata;
+
+    /**
+     * Encodes the specified NodeLocationMetadata message. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @param message NodeLocationMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified NodeLocationMetadata message, length delimited. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @param message NodeLocationMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): NodeLocationMetadata;
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): NodeLocationMetadata;
+
+    /**
+     * Verifies a NodeLocationMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a NodeLocationMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns NodeLocationMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): NodeLocationMetadata;
+
+    /**
+     * Creates a plain object from a NodeLocationMetadata message. Also converts values to other types if specified.
+     * @param message NodeLocationMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: NodeLocationMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this NodeLocationMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a StorageBucketOperatorMetadata. */
+export interface IStorageBucketOperatorMetadata {
+
+    /** StorageBucketOperatorMetadata endpoint */
+    endpoint?: (string|null);
+
+    /** StorageBucketOperatorMetadata location */
+    location?: (INodeLocationMetadata|null);
+
+    /** StorageBucketOperatorMetadata extra */
+    extra?: (string|null);
+}
+
+/** Represents a StorageBucketOperatorMetadata. */
+export class StorageBucketOperatorMetadata implements IStorageBucketOperatorMetadata {
+
+    /**
+     * Constructs a new StorageBucketOperatorMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IStorageBucketOperatorMetadata);
+
+    /** StorageBucketOperatorMetadata endpoint. */
+    public endpoint: string;
+
+    /** StorageBucketOperatorMetadata location. */
+    public location?: (INodeLocationMetadata|null);
+
+    /** StorageBucketOperatorMetadata extra. */
+    public extra: string;
+
+    /**
+     * Creates a new StorageBucketOperatorMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns StorageBucketOperatorMetadata instance
+     */
+    public static create(properties?: IStorageBucketOperatorMetadata): StorageBucketOperatorMetadata;
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message, length delimited. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): StorageBucketOperatorMetadata;
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): StorageBucketOperatorMetadata;
+
+    /**
+     * Verifies a StorageBucketOperatorMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a StorageBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns StorageBucketOperatorMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): StorageBucketOperatorMetadata;
+
+    /**
+     * Creates a plain object from a StorageBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @param message StorageBucketOperatorMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: StorageBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this StorageBucketOperatorMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a DistributionBucketOperatorMetadata. */
+export interface IDistributionBucketOperatorMetadata {
+
+    /** DistributionBucketOperatorMetadata endpoint */
+    endpoint?: (string|null);
+
+    /** DistributionBucketOperatorMetadata location */
+    location?: (INodeLocationMetadata|null);
+
+    /** DistributionBucketOperatorMetadata extra */
+    extra?: (string|null);
+}
+
+/** Represents a DistributionBucketOperatorMetadata. */
+export class DistributionBucketOperatorMetadata implements IDistributionBucketOperatorMetadata {
+
+    /**
+     * Constructs a new DistributionBucketOperatorMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IDistributionBucketOperatorMetadata);
+
+    /** DistributionBucketOperatorMetadata endpoint. */
+    public endpoint: string;
+
+    /** DistributionBucketOperatorMetadata location. */
+    public location?: (INodeLocationMetadata|null);
+
+    /** DistributionBucketOperatorMetadata extra. */
+    public extra: string;
+
+    /**
+     * Creates a new DistributionBucketOperatorMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns DistributionBucketOperatorMetadata instance
+     */
+    public static create(properties?: IDistributionBucketOperatorMetadata): DistributionBucketOperatorMetadata;
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message, length delimited. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketOperatorMetadata;
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketOperatorMetadata;
+
+    /**
+     * Verifies a DistributionBucketOperatorMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a DistributionBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns DistributionBucketOperatorMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): DistributionBucketOperatorMetadata;
+
+    /**
+     * Creates a plain object from a DistributionBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @param message DistributionBucketOperatorMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: DistributionBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this DistributionBucketOperatorMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a DistributionBucketFamilyMetadata. */
+export interface IDistributionBucketFamilyMetadata {
+
+    /** DistributionBucketFamilyMetadata region */
+    region?: (string|null);
+
+    /** DistributionBucketFamilyMetadata description */
+    description?: (string|null);
+
+    /** DistributionBucketFamilyMetadata boundary */
+    boundary?: (IGeoCoordiantes[]|null);
+}
+
+/** Represents a DistributionBucketFamilyMetadata. */
+export class DistributionBucketFamilyMetadata implements IDistributionBucketFamilyMetadata {
+
+    /**
+     * Constructs a new DistributionBucketFamilyMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IDistributionBucketFamilyMetadata);
+
+    /** DistributionBucketFamilyMetadata region. */
+    public region: string;
+
+    /** DistributionBucketFamilyMetadata description. */
+    public description: string;
+
+    /** DistributionBucketFamilyMetadata boundary. */
+    public boundary: IGeoCoordiantes[];
+
+    /**
+     * Creates a new DistributionBucketFamilyMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns DistributionBucketFamilyMetadata instance
+     */
+    public static create(properties?: IDistributionBucketFamilyMetadata): DistributionBucketFamilyMetadata;
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message, length delimited. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketFamilyMetadata;
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketFamilyMetadata;
+
+    /**
+     * Verifies a DistributionBucketFamilyMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a DistributionBucketFamilyMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns DistributionBucketFamilyMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): DistributionBucketFamilyMetadata;
 
-    /** GeoCoordiantes longitude */
-    longitude?: (number|null);
+    /**
+     * Creates a plain object from a DistributionBucketFamilyMetadata message. Also converts values to other types if specified.
+     * @param message DistributionBucketFamilyMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: DistributionBucketFamilyMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this DistributionBucketFamilyMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
 }
 
-/** Represents a GeoCoordiantes. */
-export class GeoCoordiantes implements IGeoCoordiantes {
+/** Properties of a PublishedBeforeJoystream. */
+export interface IPublishedBeforeJoystream {
+
+    /** PublishedBeforeJoystream isPublished */
+    isPublished?: (boolean|null);
+
+    /** PublishedBeforeJoystream date */
+    date?: (string|null);
+}
+
+/** Represents a PublishedBeforeJoystream. */
+export class PublishedBeforeJoystream implements IPublishedBeforeJoystream {
 
     /**
-     * Constructs a new GeoCoordiantes.
+     * Constructs a new PublishedBeforeJoystream.
      * @param [properties] Properties to set
      */
-    constructor(properties?: IGeoCoordiantes);
+    constructor(properties?: IPublishedBeforeJoystream);
 
-    /** GeoCoordiantes latitude. */
-    public latitude: number;
+    /** PublishedBeforeJoystream isPublished. */
+    public isPublished: boolean;
 
-    /** GeoCoordiantes longitude. */
-    public longitude: number;
+    /** PublishedBeforeJoystream date. */
+    public date: string;
 
     /**
-     * Creates a new GeoCoordiantes instance using the specified properties.
+     * Creates a new PublishedBeforeJoystream instance using the specified properties.
      * @param [properties] Properties to set
-     * @returns GeoCoordiantes instance
+     * @returns PublishedBeforeJoystream instance
      */
-    public static create(properties?: IGeoCoordiantes): GeoCoordiantes;
+    public static create(properties?: IPublishedBeforeJoystream): PublishedBeforeJoystream;
 
     /**
-     * Encodes the specified GeoCoordiantes message. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
-     * @param message GeoCoordiantes message or plain object to encode
+     * Encodes the specified PublishedBeforeJoystream message. Does not implicitly {@link PublishedBeforeJoystream.verify|verify} messages.
+     * @param message PublishedBeforeJoystream message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encode(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encode(message: IPublishedBeforeJoystream, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Encodes the specified GeoCoordiantes message, length delimited. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
-     * @param message GeoCoordiantes message or plain object to encode
+     * Encodes the specified PublishedBeforeJoystream message, length delimited. Does not implicitly {@link PublishedBeforeJoystream.verify|verify} messages.
+     * @param message PublishedBeforeJoystream message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encodeDelimited(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IPublishedBeforeJoystream, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Decodes a GeoCoordiantes message from the specified reader or buffer.
+     * Decodes a PublishedBeforeJoystream message from the specified reader or buffer.
      * @param reader Reader or buffer to decode from
      * @param [length] Message length if known beforehand
-     * @returns GeoCoordiantes
+     * @returns PublishedBeforeJoystream
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): GeoCoordiantes;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): PublishedBeforeJoystream;
 
     /**
-     * Decodes a GeoCoordiantes message from the specified reader or buffer, length delimited.
+     * Decodes a PublishedBeforeJoystream message from the specified reader or buffer, length delimited.
      * @param reader Reader or buffer to decode from
-     * @returns GeoCoordiantes
+     * @returns PublishedBeforeJoystream
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): GeoCoordiantes;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): PublishedBeforeJoystream;
 
     /**
-     * Verifies a GeoCoordiantes message.
+     * Verifies a PublishedBeforeJoystream message.
      * @param message Plain object to verify
      * @returns `null` if valid, otherwise the reason why it is not
      */
     public static verify(message: { [k: string]: any }): (string|null);
 
     /**
-     * Creates a GeoCoordiantes message from a plain object. Also converts values to their respective internal types.
+     * Creates a PublishedBeforeJoystream message from a plain object. Also converts values to their respective internal types.
      * @param object Plain object
-     * @returns GeoCoordiantes
+     * @returns PublishedBeforeJoystream
      */
-    public static fromObject(object: { [k: string]: any }): GeoCoordiantes;
+    public static fromObject(object: { [k: string]: any }): PublishedBeforeJoystream;
 
     /**
-     * Creates a plain object from a GeoCoordiantes message. Also converts values to other types if specified.
-     * @param message GeoCoordiantes
+     * Creates a plain object from a PublishedBeforeJoystream message. Also converts values to other types if specified.
+     * @param message PublishedBeforeJoystream
      * @param [options] Conversion options
      * @returns Plain object
      */
-    public static toObject(message: GeoCoordiantes, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public static toObject(message: PublishedBeforeJoystream, options?: $protobuf.IConversionOptions): { [k: string]: any };
 
     /**
-     * Converts this GeoCoordiantes to JSON.
+     * Converts this PublishedBeforeJoystream to JSON.
      * @returns JSON object
      */
     public toJSON(): { [k: string]: any };
 }
 
-/** Properties of a NodeLocationMetadata. */
-export interface INodeLocationMetadata {
+/** Properties of a License. */
+export interface ILicense {
 
-    /** NodeLocationMetadata countryCode */
-    countryCode?: (string|null);
+    /** License code */
+    code?: (number|null);
 
-    /** NodeLocationMetadata city */
-    city?: (string|null);
+    /** License attribution */
+    attribution?: (string|null);
 
-    /** NodeLocationMetadata coordinates */
-    coordinates?: (IGeoCoordiantes|null);
+    /** License customText */
+    customText?: (string|null);
 }
 
-/** Represents a NodeLocationMetadata. */
-export class NodeLocationMetadata implements INodeLocationMetadata {
+/** Represents a License. */
+export class License implements ILicense {
 
     /**
-     * Constructs a new NodeLocationMetadata.
+     * Constructs a new License.
      * @param [properties] Properties to set
      */
-    constructor(properties?: INodeLocationMetadata);
+    constructor(properties?: ILicense);
 
-    /** NodeLocationMetadata countryCode. */
-    public countryCode: string;
+    /** License code. */
+    public code: number;
 
-    /** NodeLocationMetadata city. */
-    public city: string;
+    /** License attribution. */
+    public attribution: string;
 
-    /** NodeLocationMetadata coordinates. */
-    public coordinates?: (IGeoCoordiantes|null);
+    /** License customText. */
+    public customText: string;
 
     /**
-     * Creates a new NodeLocationMetadata instance using the specified properties.
+     * Creates a new License instance using the specified properties.
      * @param [properties] Properties to set
-     * @returns NodeLocationMetadata instance
+     * @returns License instance
      */
-    public static create(properties?: INodeLocationMetadata): NodeLocationMetadata;
+    public static create(properties?: ILicense): License;
 
     /**
-     * Encodes the specified NodeLocationMetadata message. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
-     * @param message NodeLocationMetadata message or plain object to encode
+     * Encodes the specified License message. Does not implicitly {@link License.verify|verify} messages.
+     * @param message License message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encode(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encode(message: ILicense, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Encodes the specified NodeLocationMetadata message, length delimited. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
-     * @param message NodeLocationMetadata message or plain object to encode
+     * Encodes the specified License message, length delimited. Does not implicitly {@link License.verify|verify} messages.
+     * @param message License message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encodeDelimited(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: ILicense, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Decodes a NodeLocationMetadata message from the specified reader or buffer.
+     * Decodes a License message from the specified reader or buffer.
      * @param reader Reader or buffer to decode from
      * @param [length] Message length if known beforehand
-     * @returns NodeLocationMetadata
+     * @returns License
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): NodeLocationMetadata;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): License;
 
     /**
-     * Decodes a NodeLocationMetadata message from the specified reader or buffer, length delimited.
+     * Decodes a License message from the specified reader or buffer, length delimited.
      * @param reader Reader or buffer to decode from
-     * @returns NodeLocationMetadata
+     * @returns License
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): NodeLocationMetadata;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): License;
 
     /**
-     * Verifies a NodeLocationMetadata message.
+     * Verifies a License message.
      * @param message Plain object to verify
      * @returns `null` if valid, otherwise the reason why it is not
      */
     public static verify(message: { [k: string]: any }): (string|null);
 
     /**
-     * Creates a NodeLocationMetadata message from a plain object. Also converts values to their respective internal types.
+     * Creates a License message from a plain object. Also converts values to their respective internal types.
      * @param object Plain object
-     * @returns NodeLocationMetadata
+     * @returns License
      */
-    public static fromObject(object: { [k: string]: any }): NodeLocationMetadata;
+    public static fromObject(object: { [k: string]: any }): License;
 
     /**
-     * Creates a plain object from a NodeLocationMetadata message. Also converts values to other types if specified.
-     * @param message NodeLocationMetadata
+     * Creates a plain object from a License message. Also converts values to other types if specified.
+     * @param message License
      * @param [options] Conversion options
      * @returns Plain object
      */
-    public static toObject(message: NodeLocationMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public static toObject(message: License, options?: $protobuf.IConversionOptions): { [k: string]: any };
 
     /**
-     * Converts this NodeLocationMetadata to JSON.
+     * Converts this License to JSON.
      * @returns JSON object
      */
     public toJSON(): { [k: string]: any };
 }
 
-/** Properties of a StorageBucketOperatorMetadata. */
-export interface IStorageBucketOperatorMetadata {
+/** Properties of a MediaType. */
+export interface IMediaType {
 
-    /** StorageBucketOperatorMetadata endpoint */
-    endpoint?: (string|null);
+    /** MediaType codecName */
+    codecName?: (string|null);
 
-    /** StorageBucketOperatorMetadata location */
-    location?: (INodeLocationMetadata|null);
+    /** MediaType container */
+    container?: (string|null);
 
-    /** StorageBucketOperatorMetadata extra */
-    extra?: (string|null);
+    /** MediaType mimeMediaType */
+    mimeMediaType?: (string|null);
 }
 
-/** Represents a StorageBucketOperatorMetadata. */
-export class StorageBucketOperatorMetadata implements IStorageBucketOperatorMetadata {
+/** Represents a MediaType. */
+export class MediaType implements IMediaType {
 
     /**
-     * Constructs a new StorageBucketOperatorMetadata.
+     * Constructs a new MediaType.
      * @param [properties] Properties to set
      */
-    constructor(properties?: IStorageBucketOperatorMetadata);
+    constructor(properties?: IMediaType);
 
-    /** StorageBucketOperatorMetadata endpoint. */
-    public endpoint: string;
+    /** MediaType codecName. */
+    public codecName: string;
 
-    /** StorageBucketOperatorMetadata location. */
-    public location?: (INodeLocationMetadata|null);
+    /** MediaType container. */
+    public container: string;
 
-    /** StorageBucketOperatorMetadata extra. */
-    public extra: string;
+    /** MediaType mimeMediaType. */
+    public mimeMediaType: string;
 
     /**
-     * Creates a new StorageBucketOperatorMetadata instance using the specified properties.
+     * Creates a new MediaType instance using the specified properties.
      * @param [properties] Properties to set
-     * @returns StorageBucketOperatorMetadata instance
+     * @returns MediaType instance
      */
-    public static create(properties?: IStorageBucketOperatorMetadata): StorageBucketOperatorMetadata;
+    public static create(properties?: IMediaType): MediaType;
 
     /**
-     * Encodes the specified StorageBucketOperatorMetadata message. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
-     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * Encodes the specified MediaType message. Does not implicitly {@link MediaType.verify|verify} messages.
+     * @param message MediaType message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encode(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encode(message: IMediaType, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Encodes the specified StorageBucketOperatorMetadata message, length delimited. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
-     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * Encodes the specified MediaType message, length delimited. Does not implicitly {@link MediaType.verify|verify} messages.
+     * @param message MediaType message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encodeDelimited(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IMediaType, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer.
+     * Decodes a MediaType message from the specified reader or buffer.
      * @param reader Reader or buffer to decode from
      * @param [length] Message length if known beforehand
-     * @returns StorageBucketOperatorMetadata
+     * @returns MediaType
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): StorageBucketOperatorMetadata;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): MediaType;
 
     /**
-     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * Decodes a MediaType message from the specified reader or buffer, length delimited.
      * @param reader Reader or buffer to decode from
-     * @returns StorageBucketOperatorMetadata
+     * @returns MediaType
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): StorageBucketOperatorMetadata;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): MediaType;
 
     /**
-     * Verifies a StorageBucketOperatorMetadata message.
+     * Verifies a MediaType message.
      * @param message Plain object to verify
      * @returns `null` if valid, otherwise the reason why it is not
      */
     public static verify(message: { [k: string]: any }): (string|null);
 
     /**
-     * Creates a StorageBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * Creates a MediaType message from a plain object. Also converts values to their respective internal types.
      * @param object Plain object
-     * @returns StorageBucketOperatorMetadata
+     * @returns MediaType
      */
-    public static fromObject(object: { [k: string]: any }): StorageBucketOperatorMetadata;
+    public static fromObject(object: { [k: string]: any }): MediaType;
 
     /**
-     * Creates a plain object from a StorageBucketOperatorMetadata message. Also converts values to other types if specified.
-     * @param message StorageBucketOperatorMetadata
+     * Creates a plain object from a MediaType message. Also converts values to other types if specified.
+     * @param message MediaType
      * @param [options] Conversion options
      * @returns Plain object
      */
-    public static toObject(message: StorageBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public static toObject(message: MediaType, options?: $protobuf.IConversionOptions): { [k: string]: any };
 
     /**
-     * Converts this StorageBucketOperatorMetadata to JSON.
+     * Converts this MediaType to JSON.
      * @returns JSON object
      */
     public toJSON(): { [k: string]: any };
 }
 
-/** Properties of a DistributionBucketOperatorMetadata. */
-export interface IDistributionBucketOperatorMetadata {
+/** Properties of a VideoMetadata. */
+export interface IVideoMetadata {
 
-    /** DistributionBucketOperatorMetadata endpoint */
-    endpoint?: (string|null);
+    /** VideoMetadata title */
+    title?: (string|null);
 
-    /** DistributionBucketOperatorMetadata location */
-    location?: (INodeLocationMetadata|null);
+    /** VideoMetadata description */
+    description?: (string|null);
 
-    /** DistributionBucketOperatorMetadata extra */
-    extra?: (string|null);
+    /** VideoMetadata video */
+    video?: (number|null);
+
+    /** VideoMetadata thumbnailPhoto */
+    thumbnailPhoto?: (number|null);
+
+    /** VideoMetadata duration */
+    duration?: (number|null);
+
+    /** VideoMetadata mediaPixelHeight */
+    mediaPixelHeight?: (number|null);
+
+    /** VideoMetadata mediaPixelWidth */
+    mediaPixelWidth?: (number|null);
+
+    /** VideoMetadata mediaType */
+    mediaType?: (IMediaType|null);
+
+    /** VideoMetadata language */
+    language?: (string|null);
+
+    /** VideoMetadata license */
+    license?: (ILicense|null);
+
+    /** VideoMetadata publishedBeforeJoystream */
+    publishedBeforeJoystream?: (IPublishedBeforeJoystream|null);
+
+    /** VideoMetadata hasMarketing */
+    hasMarketing?: (boolean|null);
+
+    /** VideoMetadata isPublic */
+    isPublic?: (boolean|null);
+
+    /** VideoMetadata isExplicit */
+    isExplicit?: (boolean|null);
+
+    /** VideoMetadata persons */
+    persons?: (Long[]|null);
+
+    /** VideoMetadata category */
+    category?: (Long|null);
 }
 
-/** Represents a DistributionBucketOperatorMetadata. */
-export class DistributionBucketOperatorMetadata implements IDistributionBucketOperatorMetadata {
+/** Represents a VideoMetadata. */
+export class VideoMetadata implements IVideoMetadata {
 
     /**
-     * Constructs a new DistributionBucketOperatorMetadata.
+     * Constructs a new VideoMetadata.
      * @param [properties] Properties to set
      */
-    constructor(properties?: IDistributionBucketOperatorMetadata);
+    constructor(properties?: IVideoMetadata);
 
-    /** DistributionBucketOperatorMetadata endpoint. */
-    public endpoint: string;
+    /** VideoMetadata title. */
+    public title: string;
 
-    /** DistributionBucketOperatorMetadata location. */
-    public location?: (INodeLocationMetadata|null);
+    /** VideoMetadata description. */
+    public description: string;
 
-    /** DistributionBucketOperatorMetadata extra. */
-    public extra: string;
+    /** VideoMetadata video. */
+    public video: number;
+
+    /** VideoMetadata thumbnailPhoto. */
+    public thumbnailPhoto: number;
+
+    /** VideoMetadata duration. */
+    public duration: number;
+
+    /** VideoMetadata mediaPixelHeight. */
+    public mediaPixelHeight: number;
+
+    /** VideoMetadata mediaPixelWidth. */
+    public mediaPixelWidth: number;
+
+    /** VideoMetadata mediaType. */
+    public mediaType?: (IMediaType|null);
+
+    /** VideoMetadata language. */
+    public language: string;
+
+    /** VideoMetadata license. */
+    public license?: (ILicense|null);
+
+    /** VideoMetadata publishedBeforeJoystream. */
+    public publishedBeforeJoystream?: (IPublishedBeforeJoystream|null);
+
+    /** VideoMetadata hasMarketing. */
+    public hasMarketing: boolean;
+
+    /** VideoMetadata isPublic. */
+    public isPublic: boolean;
+
+    /** VideoMetadata isExplicit. */
+    public isExplicit: boolean;
+
+    /** VideoMetadata persons. */
+    public persons: Long[];
+
+    /** VideoMetadata category. */
+    public category: Long;
 
     /**
-     * Creates a new DistributionBucketOperatorMetadata instance using the specified properties.
+     * Creates a new VideoMetadata instance using the specified properties.
      * @param [properties] Properties to set
-     * @returns DistributionBucketOperatorMetadata instance
+     * @returns VideoMetadata instance
      */
-    public static create(properties?: IDistributionBucketOperatorMetadata): DistributionBucketOperatorMetadata;
+    public static create(properties?: IVideoMetadata): VideoMetadata;
 
     /**
-     * Encodes the specified DistributionBucketOperatorMetadata message. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
-     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * Encodes the specified VideoMetadata message. Does not implicitly {@link VideoMetadata.verify|verify} messages.
+     * @param message VideoMetadata message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encode(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encode(message: IVideoMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Encodes the specified DistributionBucketOperatorMetadata message, length delimited. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
-     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * Encodes the specified VideoMetadata message, length delimited. Does not implicitly {@link VideoMetadata.verify|verify} messages.
+     * @param message VideoMetadata message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encodeDelimited(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IVideoMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer.
+     * Decodes a VideoMetadata message from the specified reader or buffer.
      * @param reader Reader or buffer to decode from
      * @param [length] Message length if known beforehand
-     * @returns DistributionBucketOperatorMetadata
+     * @returns VideoMetadata
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketOperatorMetadata;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): VideoMetadata;
 
     /**
-     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * Decodes a VideoMetadata message from the specified reader or buffer, length delimited.
      * @param reader Reader or buffer to decode from
-     * @returns DistributionBucketOperatorMetadata
+     * @returns VideoMetadata
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketOperatorMetadata;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): VideoMetadata;
 
     /**
-     * Verifies a DistributionBucketOperatorMetadata message.
+     * Verifies a VideoMetadata message.
      * @param message Plain object to verify
      * @returns `null` if valid, otherwise the reason why it is not
      */
     public static verify(message: { [k: string]: any }): (string|null);
 
     /**
-     * Creates a DistributionBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * Creates a VideoMetadata message from a plain object. Also converts values to their respective internal types.
      * @param object Plain object
-     * @returns DistributionBucketOperatorMetadata
+     * @returns VideoMetadata
      */
-    public static fromObject(object: { [k: string]: any }): DistributionBucketOperatorMetadata;
+    public static fromObject(object: { [k: string]: any }): VideoMetadata;
 
     /**
-     * Creates a plain object from a DistributionBucketOperatorMetadata message. Also converts values to other types if specified.
-     * @param message DistributionBucketOperatorMetadata
+     * Creates a plain object from a VideoMetadata message. Also converts values to other types if specified.
+     * @param message VideoMetadata
      * @param [options] Conversion options
      * @returns Plain object
      */
-    public static toObject(message: DistributionBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public static toObject(message: VideoMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
 
     /**
-     * Converts this DistributionBucketOperatorMetadata to JSON.
+     * Converts this VideoMetadata to JSON.
      * @returns JSON object
      */
     public toJSON(): { [k: string]: any };
 }
 
-/** Properties of a DistributionBucketFamilyMetadata. */
-export interface IDistributionBucketFamilyMetadata {
-
-    /** DistributionBucketFamilyMetadata region */
-    region?: (string|null);
-
-    /** DistributionBucketFamilyMetadata description */
-    description?: (string|null);
+/** Properties of a VideoCategoryMetadata. */
+export interface IVideoCategoryMetadata {
 
-    /** DistributionBucketFamilyMetadata boundary */
-    boundary?: (IGeoCoordiantes[]|null);
+    /** VideoCategoryMetadata name */
+    name?: (string|null);
 }
 
-/** Represents a DistributionBucketFamilyMetadata. */
-export class DistributionBucketFamilyMetadata implements IDistributionBucketFamilyMetadata {
+/** Represents a VideoCategoryMetadata. */
+export class VideoCategoryMetadata implements IVideoCategoryMetadata {
 
     /**
-     * Constructs a new DistributionBucketFamilyMetadata.
+     * Constructs a new VideoCategoryMetadata.
      * @param [properties] Properties to set
      */
-    constructor(properties?: IDistributionBucketFamilyMetadata);
-
-    /** DistributionBucketFamilyMetadata region. */
-    public region: string;
+    constructor(properties?: IVideoCategoryMetadata);
 
-    /** DistributionBucketFamilyMetadata description. */
-    public description: string;
-
-    /** DistributionBucketFamilyMetadata boundary. */
-    public boundary: IGeoCoordiantes[];
+    /** VideoCategoryMetadata name. */
+    public name: string;
 
     /**
-     * Creates a new DistributionBucketFamilyMetadata instance using the specified properties.
+     * Creates a new VideoCategoryMetadata instance using the specified properties.
      * @param [properties] Properties to set
-     * @returns DistributionBucketFamilyMetadata instance
+     * @returns VideoCategoryMetadata instance
      */
-    public static create(properties?: IDistributionBucketFamilyMetadata): DistributionBucketFamilyMetadata;
+    public static create(properties?: IVideoCategoryMetadata): VideoCategoryMetadata;
 
     /**
-     * Encodes the specified DistributionBucketFamilyMetadata message. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
-     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * Encodes the specified VideoCategoryMetadata message. Does not implicitly {@link VideoCategoryMetadata.verify|verify} messages.
+     * @param message VideoCategoryMetadata message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encode(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encode(message: IVideoCategoryMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Encodes the specified DistributionBucketFamilyMetadata message, length delimited. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
-     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * Encodes the specified VideoCategoryMetadata message, length delimited. Does not implicitly {@link VideoCategoryMetadata.verify|verify} messages.
+     * @param message VideoCategoryMetadata message or plain object to encode
      * @param [writer] Writer to encode to
      * @returns Writer
      */
-    public static encodeDelimited(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+    public static encodeDelimited(message: IVideoCategoryMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
 
     /**
-     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer.
+     * Decodes a VideoCategoryMetadata message from the specified reader or buffer.
      * @param reader Reader or buffer to decode from
      * @param [length] Message length if known beforehand
-     * @returns DistributionBucketFamilyMetadata
+     * @returns VideoCategoryMetadata
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketFamilyMetadata;
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): VideoCategoryMetadata;
 
     /**
-     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer, length delimited.
+     * Decodes a VideoCategoryMetadata message from the specified reader or buffer, length delimited.
      * @param reader Reader or buffer to decode from
-     * @returns DistributionBucketFamilyMetadata
+     * @returns VideoCategoryMetadata
      * @throws {Error} If the payload is not a reader or valid buffer
      * @throws {$protobuf.util.ProtocolError} If required fields are missing
      */
-    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketFamilyMetadata;
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): VideoCategoryMetadata;
 
     /**
-     * Verifies a DistributionBucketFamilyMetadata message.
+     * Verifies a VideoCategoryMetadata message.
      * @param message Plain object to verify
      * @returns `null` if valid, otherwise the reason why it is not
      */
     public static verify(message: { [k: string]: any }): (string|null);
 
     /**
-     * Creates a DistributionBucketFamilyMetadata message from a plain object. Also converts values to their respective internal types.
+     * Creates a VideoCategoryMetadata message from a plain object. Also converts values to their respective internal types.
      * @param object Plain object
-     * @returns DistributionBucketFamilyMetadata
+     * @returns VideoCategoryMetadata
      */
-    public static fromObject(object: { [k: string]: any }): DistributionBucketFamilyMetadata;
+    public static fromObject(object: { [k: string]: any }): VideoCategoryMetadata;
 
     /**
-     * Creates a plain object from a DistributionBucketFamilyMetadata message. Also converts values to other types if specified.
-     * @param message DistributionBucketFamilyMetadata
+     * Creates a plain object from a VideoCategoryMetadata message. Also converts values to other types if specified.
+     * @param message VideoCategoryMetadata
      * @param [options] Conversion options
      * @returns Plain object
      */
-    public static toObject(message: DistributionBucketFamilyMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+    public static toObject(message: VideoCategoryMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
 
     /**
-     * Converts this DistributionBucketFamilyMetadata to JSON.
+     * Converts this VideoCategoryMetadata to JSON.
      * @returns JSON object
      */
     public toJSON(): { [k: string]: any };

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 450 - 315
metadata-protobuf/compiled/index.js


+ 0 - 0
content-metadata-protobuf/doc-appendix.md → metadata-protobuf/doc-appendix.md


+ 351 - 6
metadata-protobuf/doc/index.md

@@ -3,6 +3,20 @@
 
 ## Table of Contents
 
+- [proto/Channel.proto](#proto/Channel.proto)
+    - [ChannelCategoryMetadata](#.ChannelCategoryMetadata)
+    - [ChannelMetadata](#.ChannelMetadata)
+  
+- [proto/Person.proto](#proto/Person.proto)
+    - [PersonMetadata](#.PersonMetadata)
+  
+- [proto/Playlist.proto](#proto/Playlist.proto)
+    - [PlaylistMetadata](#.PlaylistMetadata)
+  
+- [proto/Series.proto](#proto/Series.proto)
+    - [SeasonMetadata](#.SeasonMetadata)
+    - [SeriesMetadata](#.SeriesMetadata)
+  
 - [proto/Storage.proto](#proto/Storage.proto)
     - [DistributionBucketFamilyMetadata](#.DistributionBucketFamilyMetadata)
     - [DistributionBucketOperatorMetadata](#.DistributionBucketOperatorMetadata)
@@ -10,10 +24,189 @@
     - [NodeLocationMetadata](#.NodeLocationMetadata)
     - [StorageBucketOperatorMetadata](#.StorageBucketOperatorMetadata)
   
+- [proto/Video.proto](#proto/Video.proto)
+    - [License](#.License)
+    - [MediaType](#.MediaType)
+    - [PublishedBeforeJoystream](#.PublishedBeforeJoystream)
+    - [VideoCategoryMetadata](#.VideoCategoryMetadata)
+    - [VideoMetadata](#.VideoMetadata)
+  
 - [Scalar Value Types](#scalar-value-types)
 
 
 
+<a name="proto/Channel.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Channel.proto
+
+
+
+<a name=".ChannelCategoryMetadata"></a>
+
+### ChannelCategoryMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| name | [string](#string) | optional | Category Name |
+
+
+
+
+
+
+<a name=".ChannelMetadata"></a>
+
+### ChannelMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| title | [string](#string) | optional | Channel Title |
+| description | [string](#string) | optional | Channel Description |
+| is_public | [bool](#bool) | optional | Wether to display channel to the public |
+| language | [string](#string) | optional | ISO_639-1 Language [Code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) |
+| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| avatar_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| category | [uint64](#uint64) | optional | Channel Category Id |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+<a name="proto/Person.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Person.proto
+
+
+
+<a name=".PersonMetadata"></a>
+
+### PersonMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| first_name | [string](#string) | optional |  |
+| middle_name | [string](#string) | optional |  |
+| last_name | [string](#string) | optional |  |
+| about | [string](#string) | optional |  |
+| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| avatar_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+<a name="proto/Playlist.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Playlist.proto
+
+
+
+<a name=".PlaylistMetadata"></a>
+
+### PlaylistMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| title | [string](#string) | optional |  |
+| videos | [uint64](#uint64) | repeated | Videos in the playlist |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+<a name="proto/Series.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Series.proto
+
+
+
+<a name=".SeasonMetadata"></a>
+
+### SeasonMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| title | [string](#string) | optional |  |
+| description | [string](#string) | optional |  |
+| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this Season |
+
+
+
+
+
+
+<a name=".SeriesMetadata"></a>
+
+### SeriesMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| title | [string](#string) | optional |  |
+| description | [string](#string) | optional |  |
+| cover_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this Series |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
 <a name="proto/Storage.proto"></a>
 <p align="right"><a href="#top">Top</a></p>
 
@@ -31,7 +224,7 @@
 | ----- | ---- | ----- | ----------- |
 | region | [string](#string) | optional | ID / name of the region covered by the distribution family (ie. us-east-1). Should be unique. |
 | description | [string](#string) | optional | Additional, more specific description of the region |
-| boundary | [GeoCoordiantes](#GeoCoordiantes) | repeated | Geographical boundary of the region, defined as polygon through array of coordinates |
+| boundary | [GeoCoordiantes](#GeoCoordiantes) | repeated | Geographical boundary of the region, defined as polygon through array of coordinates (providing [{}] will unset the current value) |
 
 
 
@@ -47,7 +240,7 @@
 | Field | Type | Label | Description |
 | ----- | ---- | ----- | ----------- |
 | endpoint | [string](#string) | optional | Root distribution node endpoint (ie. https://example.com/distribution) |
-| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location |
+| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location (providing {} will unset current value) |
 | extra | [string](#string) | optional | Additional information about the node / node operator |
 
 
@@ -63,8 +256,8 @@
 
 | Field | Type | Label | Description |
 | ----- | ---- | ----- | ----------- |
-| latitude | [float](#float) | required |  |
-| longitude | [float](#float) | required |  |
+| latitude | [float](#float) | optional |  |
+| longitude | [float](#float) | optional |  |
 
 
 
@@ -81,7 +274,7 @@
 | ----- | ---- | ----- | ----------- |
 | country_code | [string](#string) | optional | ISO 3166-1 alpha-2 country code (2 letters) |
 | city | [string](#string) | optional | City name |
-| coordinates | [GeoCoordiantes](#GeoCoordiantes) | optional | Geographic coordinates |
+| coordinates | [GeoCoordiantes](#GeoCoordiantes) | optional | Geographic coordinates (providing {} will unset current value) |
 
 
 
@@ -97,7 +290,7 @@
 | Field | Type | Label | Description |
 | ----- | ---- | ----- | ----------- |
 | endpoint | [string](#string) | optional | Root storage node endpoint (ie. https://example.com/storage) |
-| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location |
+| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location (providing {} will unset current value) |
 | extra | [string](#string) | optional | Additional information about the node / node operator |
 
 
@@ -114,6 +307,117 @@
 
 
 
+<a name="proto/Video.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Video.proto
+
+
+
+<a name=".License"></a>
+
+### License
+License types defined by Joystream
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| code | [uint32](#uint32) | optional | License code defined by Joystream. [reference](../src/KnownLicenses.json) |
+| attribution | [string](#string) | optional | Text for licenses that require an attribution |
+| custom_text | [string](#string) | optional | Text for custom license type |
+
+
+
+
+
+
+<a name=".MediaType"></a>
+
+### MediaType
+Codec, Container, MIME media-type information
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| codec_name | [string](#string) | optional | Codec corresponding to `name` field from [FFmpeg](https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/codec_desc.c) |
+| container | [string](#string) | optional | Video container format, eg. &#39;MP4&#39;, &#39;WebM&#39;, &#39;Ogg&#39; [ref](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs) |
+| mime_media_type | [string](#string) | optional | MIME Media Type, eg. &#39;video/mp4&#39; [ref](https://www.iana.org/assignments/media-types/media-types.xhtml#video) |
+
+
+
+
+
+
+<a name=".PublishedBeforeJoystream"></a>
+
+### PublishedBeforeJoystream
+Publication status before joystream
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| is_published | [bool](#bool) | optional | Was video published before joystream platform |
+| date | [string](#string) | optional | Date of publication: &#39;YYYY-MM-DD&#39; [ISO-8601](https://www.iso.org/iso-8601-date-and-time-format.html) |
+
+
+
+
+
+
+<a name=".VideoCategoryMetadata"></a>
+
+### VideoCategoryMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| name | [string](#string) | optional | Category name |
+
+
+
+
+
+
+<a name=".VideoMetadata"></a>
+
+### VideoMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| title | [string](#string) | optional | Video Title |
+| description | [string](#string) | optional | Video Description |
+| video | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| thumbnail_photo | [uint32](#uint32) | optional | index into external [assets array](#.Assets) |
+| duration | [uint32](#uint32) | optional | Lengths of video in seconds |
+| media_pixel_height | [uint32](#uint32) | optional | Resolution of the video (Height) |
+| media_pixel_width | [uint32](#uint32) | optional | Resolution of the video (Width) |
+| media_type | [MediaType](#MediaType) | optional | Encoding and Container format used |
+| language | [string](#string) | optional | ISO_639-1 Language [Code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) |
+| license | [License](#License) | optional | License type for the media |
+| published_before_joystream | [PublishedBeforeJoystream](#PublishedBeforeJoystream) | optional | Date of publication |
+| has_marketing | [bool](#bool) | optional | Does video have marketing or advertising in the stream |
+| is_public | [bool](#bool) | optional | Should video be publicy visible yet |
+| is_explicit | [bool](#bool) | optional | Does Video have explicit language or scenes |
+| persons | [uint64](#uint64) | repeated | Person(s) referenced by PersonId involved in this video |
+| category | [uint64](#uint64) | optional | Video Category Id |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
 ## Scalar Value Types
 
 | .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
@@ -134,3 +438,44 @@
 | <a name="string" /> string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
 | <a name="bytes" /> bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
 
+<!-- 
+    This extra documentation will be appended to the generated docs.
+-->
+
+## Referencing Assets
+<a name=".Assets"></a>
+
+Applications that process messages that contain a `uint32` field that references an asset such as a cover photo or video, should interpret this value as a zero based index into an array/vector that is received external (out of band) to the protobuf message.
+
+Example in context of query-node processing the runtime event `VideoCreated`
+
+```rust
+// Runtime event associated with creating a Video
+VideoCreated(video_id: VideoId, video: Video, assets: Vec<NewAsset>, params: VideoCreationParameters)
+
+struct VideoCreationParameters {
+  in_category: VideoCategoryId,
+  // binary serialized VideoMetadata protobuf message
+  meta: Vec<u8>,
+}
+
+// suppose assets is a vector of two elements. This is the "out of band" array being referenced by the VideoMetadata message
+assets = [
+    NewAsset::Uri("https://mydomain.net/thumbnail.png"),
+    NewAsset::Upload({
+       content_id,
+       ipfs_hash,
+       size,
+       ...
+    }),
+];
+
+meta = VideoMetadata {
+    ...
+    // refers to second element: assets[1] which is being uploaded to the storage system
+    video: 1,
+    // refers to the first element assets[0] which is being referneced by a url string.
+    thumbnail_photo: 0,
+    ...
+};
+```

+ 3 - 0
metadata-protobuf/generate-md-doc.sh

@@ -8,3 +8,6 @@ mkdir -p ${OUT_DIR_DOC}
 protoc \
     --doc_out="${OUT_DIR_DOC}" --doc_opt=markdown,index.md \
     proto/*.proto
+
+# Append some custom docs to generated protocol docs
+cat doc-appendix.md >> ${OUT_DIR_DOC}/index.md

+ 4 - 2
metadata-protobuf/package.json

@@ -26,7 +26,8 @@
     "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha --inline-diffs -r ts-node/register 'test/**/*.ts'",
     "lint": "eslint ./src --ext .ts",
     "checks": "tsc --noEmit --pretty && prettier ./ --check && yarn lint",
-    "format": "prettier ./ --write"
+    "format": "prettier ./ --write",
+    "prepublish": "yarn build"
   },
   "files": [
     "lib/**/*",
@@ -39,7 +40,8 @@
     "google-protobuf": "^3.14.0",
     "long": "^4.0.0",
     "@types/long": "^4.0.1",
-    "i18n-iso-countries": "^6.8.0"
+    "i18n-iso-countries": "^6.8.0",
+    "iso-639-1": "^2.1.9"
   },
   "devDependencies": {
     "@types/chai": "^4.2.11",

+ 0 - 0
content-metadata-protobuf/proto/Channel.proto → metadata-protobuf/proto/Channel.proto


+ 0 - 0
content-metadata-protobuf/proto/Person.proto → metadata-protobuf/proto/Person.proto


+ 0 - 0
content-metadata-protobuf/proto/Playlist.proto → metadata-protobuf/proto/Playlist.proto


+ 0 - 0
content-metadata-protobuf/proto/Series.proto → metadata-protobuf/proto/Series.proto


+ 0 - 0
content-metadata-protobuf/proto/Video.proto → metadata-protobuf/proto/Video.proto


+ 0 - 0
content-metadata-protobuf/src/KnownLicenses.json → metadata-protobuf/src/KnownLicenses.json


+ 4 - 10
content-metadata-protobuf/src/licenses.ts → metadata-protobuf/src/licenses.ts

@@ -2,7 +2,7 @@
 // This should be factored out into a separate package
 
 import LICENSES from './KnownLicenses.json'
-import { License } from '../compiled/proto/Video_pb'
+import { License } from '../compiled/index'
 
 export type LicenseCode = number
 export const CUSTOM_LICENSE_CODE: LicenseCode = 1000
@@ -39,26 +39,20 @@ export function createKnownLicenseFromCode(code: LicenseCode, attribution?: stri
     throw new Error('Unknown License Code')
   }
 
-  const license = new License()
-
-  license.setCode(code)
+  const license = new License({ code })
 
   if (knownLicense.attributionRequired) {
     if (attribution === undefined) {
       throw new Error('Attribution required for selected license')
     }
-    license.setAttribution(attribution)
+    license.attribution = attribution
   }
 
   return license
 }
 
 export function createCustomKnownLicense(customText: string): License {
-  const license = new License()
-
-  license.setCode(CUSTOM_LICENSE_CODE)
-  license.setCustomText(customText)
-  return license
+  return new License({ code: CUSTOM_LICENSE_CODE, customText })
 }
 
 export default {

+ 2 - 2
metadata-protobuf/src/types.ts

@@ -10,8 +10,8 @@ export type AnyMetadataClass<T> = {
   decode(binary: Uint8Array): AnyMessage<T>
   encode(obj: T): { finish(): Uint8Array }
   toObject(obj: AnyMessage<T>, options?: IConversionOptions): Record<string, unknown>
-  verify(message: { [k: string]: any }): null | string
-  fromObject(object: { [k: string]: any }): AnyMessage<T>
+  verify(message: { [k: string]: unknown }): null | string
+  fromObject(object: { [k: string]: unknown }): AnyMessage<T>
 }
 
 export type DecodedMetadataObject<T> = {

+ 8 - 2
metadata-protobuf/src/utils.ts

@@ -1,11 +1,12 @@
 import { AnyMessage, AnyMetadataClass, DecodedMetadataObject } from './types'
 import countries from 'i18n-iso-countries'
+import langs from 'iso-639-1'
 
 export function isSet<T>(v: T | null | undefined): v is T {
   return v !== null && v !== undefined
 }
 
-export function isEmptyObject(object: Record<string, any>): boolean {
+export function isEmptyObject<T>(object: T): boolean {
   return Object.keys(object).length === 0
 }
 
@@ -32,7 +33,12 @@ export function metaToObject<T>(metaClass: AnyMetadataClass<T>, value: AnyMessag
   return metaClass.toObject(value, { arrays: false, longs: String }) as DecodedMetadataObject<T>
 }
 
-// According to ISO 3166-1 alpha-2 standard
+// Checks if the provided code is valid according to ISO 3166-1 alpha-2 standard
 export function isValidCountryCode(code: string): boolean {
   return countries.getAlpha2Codes()[code] !== undefined
 }
+
+// Checks if the provided code is valid according to ISO 639-1 standard
+export function isValidLanguageCode(code: string): boolean {
+  return langs.validate(code)
+}

+ 31 - 0
metadata-protobuf/test/channel.ts

@@ -0,0 +1,31 @@
+import { ChannelMetadata } from '../src'
+import { assert } from 'chai'
+import { encodeDecode, metaToObject } from '../src/utils'
+import Long from 'long'
+
+describe('Channel Metadata', () => {
+  it('Message', () => {
+    const channel = {
+      title: 'title',
+      description: 'description',
+      isPublic: false,
+      language: 'fr',
+      avatarPhoto: 0,
+      coverPhoto: 1,
+      category: Long.fromNumber(100, true),
+    }
+    const channelMessage = new ChannelMetadata(channel)
+
+    assert.deepEqual(metaToObject(ChannelMetadata, channelMessage), { ...channel, category: '100' })
+    assert.deepEqual(encodeDecode(ChannelMetadata, channel), { ...channel, category: '100' })
+  })
+
+  it('Channel Metadata: Category as number', () => {
+    const channel = { category: 100 as any }
+    const channelMessage = new ChannelMetadata(channel)
+    ChannelMetadata.verify(channelMessage)
+
+    assert.deepEqual(metaToObject(ChannelMetadata, channelMessage), { ...channel, category: '100' })
+    assert.deepEqual(encodeDecode(ChannelMetadata, channel), { ...channel, category: '100' })
+  })
+})

+ 14 - 8
content-metadata-protobuf/test/license-codes.ts → metadata-protobuf/test/license-codes.ts

@@ -5,7 +5,7 @@ import {
   createKnownLicenseFromCode,
   createCustomKnownLicense,
 } from '../src/licenses'
-import { VideoMetadata } from '../src/index'
+import { License } from '../src/index'
 import { assert } from 'chai'
 
 describe('Known License Codes', () => {
@@ -16,7 +16,7 @@ describe('Known License Codes', () => {
   it('Pre-defined Joystream license codes', () => {
     // Make sure we have correct known custom license
     assert(KnownLicenses.has(CUSTOM_LICENSE_CODE))
-    assert.equal(KnownLicenses.get(CUSTOM_LICENSE_CODE)!.name, 'CUSTOM')
+    assert.equal(KnownLicenses.get(CUSTOM_LICENSE_CODE)?.name, 'CUSTOM')
 
     assert(KnownLicenses.has(1001))
     assert(KnownLicenses.has(1002))
@@ -29,14 +29,20 @@ describe('Known License Codes', () => {
   })
 
   it('createCustomKnownLicense(): uses correct code', () => {
-    const license = createCustomKnownLicense('custom text')
-    assert.equal(license.getCode(), CUSTOM_LICENSE_CODE)
+    const TEXT = 'custom text'
+    const license = createCustomKnownLicense(TEXT)
+    assert.equal(license.code, CUSTOM_LICENSE_CODE)
+    assert.equal(license.customText, TEXT)
+    License.verify(license)
   })
 
   it('createKnownLicenseFromCode(): License can be created by name', () => {
-    const licenseCode = getLicenseCodeByName('CC_BY') as number
-    const license = createKnownLicenseFromCode(licenseCode as number, 'Attribution: Joystream')
-    const videoMeta = new VideoMetadata()
-    videoMeta.setLicense(license)
+    const NAME = 'CC_BY'
+    const ATTRIBUTION = 'Attribution: Joystream'
+    const licenseCode = getLicenseCodeByName(NAME) as number
+    const license = createKnownLicenseFromCode(licenseCode, ATTRIBUTION)
+    assert.isDefined(license.code)
+    assert.equal(license.attribution, ATTRIBUTION)
+    License.verify(license)
   })
 })

+ 87 - 0
metadata-protobuf/test/video.ts

@@ -0,0 +1,87 @@
+import { VideoMetadata, MediaType } from '../src'
+import { assert, expect } from 'chai'
+import { isSet, encodeDecode, metaToObject } from '../src/utils'
+import Long from 'long'
+
+describe('Video Metadata', () => {
+  it('Message', () => {
+    const video = {
+      title: 'Video Title',
+      description: 'Video Description',
+      duration: 100,
+      mediaPixelHeight: 1,
+      mediaPixelWidth: 2,
+      mediaType: {},
+      language: 'en',
+      license: {},
+      publishedBeforeJoystream: {},
+      hasMarketing: true,
+      isPublic: true,
+      isExplicit: false,
+      video: 0,
+      thumbnailPhoto: 1,
+      category: Long.fromNumber(101, true),
+    }
+    const videoMessage = new VideoMetadata(video)
+
+    assert.deepEqual(metaToObject(VideoMetadata, videoMessage), { ...video, category: '101' })
+    assert.deepEqual(encodeDecode(VideoMetadata, video), { ...video, category: '101' })
+  })
+
+  it('Message: PublishedBeforeJoystream', () => {
+    const meta = new VideoMetadata()
+
+    expect(isSet(metaToObject(VideoMetadata, meta).publishedBeforeJoystream)).equals(
+      false,
+      'PublishedBeforeJoystream field should NOT be set'
+    )
+
+    const published = {
+      isPublished: true,
+      date: '1950-12-24',
+    }
+    meta.publishedBeforeJoystream = published
+
+    // Field should now be set
+    expect(isSet(metaToObject(VideoMetadata, meta).publishedBeforeJoystream)).equals(
+      true,
+      'PublishedBeforeJoystream field should be set'
+    )
+
+    assert.deepEqual(metaToObject(VideoMetadata, meta).publishedBeforeJoystream, published)
+    assert.deepEqual(encodeDecode(VideoMetadata, meta).publishedBeforeJoystream, meta.publishedBeforeJoystream)
+  })
+
+  it('Message: License', () => {
+    const license = {
+      code: 1000,
+      attribution: 'Attribution Text',
+      customText: 'Custom License Details',
+    }
+    const meta = new VideoMetadata({ license })
+    assert.deepEqual(metaToObject(VideoMetadata, meta).license, license)
+    assert.deepEqual(encodeDecode(VideoMetadata, meta).license, license)
+
+    // Empty object check
+    meta.license = {}
+    assert.deepEqual(metaToObject(VideoMetadata, meta).license, {})
+    assert.deepEqual(encodeDecode(VideoMetadata, meta).license, {})
+
+    // Unset check
+    meta.license = undefined
+    assert.deepEqual(metaToObject(VideoMetadata, meta).license, undefined)
+    assert.deepEqual(encodeDecode(VideoMetadata, meta).license, undefined)
+  })
+
+  it('Message: MediaType', () => {
+    const mediaType = {
+      codecName: 'mpeg4',
+      container: 'avi',
+      mimeMediaType: 'videp/mp4',
+    }
+    const mediaTypeMessage = new MediaType(mediaType)
+
+    assert.deepEqual(metaToObject(MediaType, mediaTypeMessage), mediaType)
+    assert.deepEqual(encodeDecode(MediaType, mediaType), mediaType)
+  })
+})

+ 0 - 1
package.json

@@ -28,7 +28,6 @@
     "query-node",
     "query-node/mappings",
     "query-node/generated/*",
-    "content-metadata-protobuf",
     "metadata-protobuf"
   ],
   "resolutions": {

+ 135 - 207
query-node/manifest.yml

@@ -11,6 +11,7 @@ typegen:
   metadata:
     source: ws://localhost:9944
   events:
+    # storage
     - storage.StorageBucketCreated
     - storage.StorageBucketInvitationAccepted
     - storage.StorageBucketsUpdatedForBag
@@ -33,7 +34,6 @@ typegen:
     - storage.DynamicBagCreated
     - storage.VoucherChanged
     - storage.StorageBucketDeleted
-    - storage.NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated
     - storage.DistributionBucketFamilyCreated
     - storage.DistributionBucketFamilyDeleted
     - storage.DistributionBucketCreated
@@ -42,233 +42,165 @@ typegen:
     - storage.DistributionBucketsUpdatedForBag
     - storage.DistributionBucketsPerBagLimitUpdated
     - storage.DistributionBucketModeUpdated
-    - storage.FamiliesInDynamicBagCreationPolicyUpdated
     - storage.DistributionBucketOperatorInvited
     - storage.DistributionBucketInvitationCancelled
     - storage.DistributionBucketInvitationAccepted
     - storage.DistributionBucketMetadataSet
     - storage.DistributionBucketOperatorRemoved
     - storage.DistributionBucketFamilyMetadataSet
-  # TODO: Sumer mappings
-  #   # membership
-  #   - members.MemberRegistered
-  #   - members.MemberUpdatedAboutText
-  #   - members.MemberUpdatedAvatar
-  #   - members.MemberUpdatedHandle
-  #   - members.MemberSetRootAccount
-  #   - members.MemberSetControllerAccount
+    # Not required:
+    # - storage.NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated
+    # - storage.FamiliesInDynamicBagCreationPolicyUpdated
 
-  #   # content directory
-  #   - content.CuratorGroupCreated
-  #   - content.CuratorGroupStatusSet
-  #   - content.CuratorAdded
-  #   - content.CuratorRemoved
-  #   - content.ChannelCreated
-  #   - content.ChannelUpdated
-  #   - content.ChannelAssetsRemoved
-  #   - content.ChannelCensorshipStatusUpdated
-  #   - content.ChannelOwnershipTransferRequested
-  #   - content.ChannelOwnershipTransferRequestWithdrawn
-  #   - content.ChannelOwnershipTransferred
-  #   - content.ChannelCategoryCreated
-  #   - content.ChannelCategoryUpdated
-  #   - content.ChannelCategoryDeleted
-  #   - content.VideoCategoryCreated
-  #   - content.VideoCategoryUpdated
-  #   - content.VideoCategoryDeleted
-  #   - content.VideoCreated
-  #   - content.VideoUpdated
-  #   - content.VideoDeleted
-  #   - content.VideoCensorshipStatusUpdated
-  #   - content.FeaturedVideosSet
+    # membership
+    - members.MemberRegistered
+    - members.MemberUpdatedAboutText
+    - members.MemberUpdatedAvatar
+    - members.MemberUpdatedHandle
+    - members.MemberSetRootAccount
+    - members.MemberSetControllerAccount
 
-  #   # storage
-  #   - data_directory.ContentAdded
-  #   - data_directory.ContentRemoved
-  #   - data_directory.ContentAccepted
-  #   - data_directory.ContentRejected
-  #   - data_directory.ContentUploadingStatusUpdated
+    # content directory
+    - content.CuratorGroupCreated
+    - content.CuratorGroupStatusSet
+    - content.CuratorAdded
+    - content.CuratorRemoved
+    - content.ChannelCreated
+    - content.ChannelUpdated
+    - content.ChannelAssetsRemoved
+    - content.ChannelCensorshipStatusUpdated
+    - content.ChannelOwnershipTransferRequested
+    - content.ChannelOwnershipTransferRequestWithdrawn
+    - content.ChannelOwnershipTransferred
+    - content.ChannelCategoryCreated
+    - content.ChannelCategoryUpdated
+    - content.ChannelCategoryDeleted
+    - content.VideoCategoryCreated
+    - content.VideoCategoryUpdated
+    - content.VideoCategoryDeleted
+    - content.VideoCreated
+    - content.VideoUpdated
+    - content.VideoDeleted
+    - content.VideoCensorshipStatusUpdated
+    - content.FeaturedVideosSet
 
-  #   # working groups
-  #   - storage_working_group.WorkerStorageUpdated
-  #   - storage_working_group.OpeningFilled
-  #   - storage_working_group.TerminatedWorker
-  #   - storage_working_group.WorkerExited
-  #   - storage_working_group.TerminatedLeader
-
-  #   - gateway_working_group.WorkerStorageUpdated
-  #   - gateway_working_group.OpeningFilled
-  #   - gateway_working_group.TerminatedWorker
-  #   - gateway_working_group.WorkerExited
-  #   - gateway_working_group.TerminatedLeader
-  # calls:
-  #   # members
-  #   - members.buyMembership
-  #   - members.addScreenedMember
-  #   - members.changeMemberAboutText
-  #   - members.changeMemberAvatar
-  #   - members.changeMemberHandle
-  #   - members.setRootAccount
-  #   - members.setControllerAccount
-  #   - members.updateMembership
-
-  #   # content directory
-  #   - content.create_curator_group
-  #   - content.set_curator_group_status
-  #   - content.add_curator_to_group
-  #   - content.remove_curator_from_group
-  #   - content.create_channel
-  #   - content.update_channel
-  #   - content.remove_channel_assets
-  #   - content.update_channel_censorship_status
-  #   - content.create_channel_category
-  #   - content.update_channel_category
-  #   - content.delete_channel_category
-  #   - content.request_channel_transfer
-  #   - content.cancel_channel_transfer_request
-  #   - content.accept_channel_transfer
-  #   - content.create_video
-  #   - content.update_video
-  #   - content.delete_video
-  #   - content.create_playlist
-  #   - content.update_playlist
-  #   - content.delete_playlist
-  #   - content.set_featured_videos
-  #   - content.create_video_category
-  #   - content.update_video_category
-  #   - content.delete_video_category
-  #   - content.remove_person_from_video
-  #   - content.update_video_censorship_status
-
-  #   # storage
-  #   - data_directory.add_content
-  #   - data_directory.remove_content
-  #   - data_directory.accept_content
-  #   - data_directory.update_content_uploading_status
-
-  #   # working groups
-  #   - storage_working_group.update_role_storage
-  #   - storage_working_group.fill_opening
-  #   - storage_working_group.leave_role
-  #   - storage_working_group.terminate_role
-
-  #   - gateway_working_group.update_role_storage
-  #   - gateway_working_group.fill_opening
-  #   - gateway_working_group.leave_role
-  #   - gateway_working_group.terminate_role
+    # working groups (we're using "storage_working_group" as a reference module)
+    - storage_working_group.WorkerStorageUpdated
+    - storage_working_group.OpeningFilled
+    - storage_working_group.TerminatedWorker
+    - storage_working_group.WorkerExited
+    - storage_working_group.TerminatedLeader
+  calls:
+    # members
+    - members.buyMembership
+    - members.addScreenedMember
+    - members.changeMemberAboutText
+    - members.changeMemberAvatar
+    - members.changeMemberHandle
+    - members.setRootAccount
+    - members.setControllerAccount
+    - members.updateMembership
   outDir: ./mappings/generated/types
   customTypes:
     lib: '@joystream/types/augment/all/types'
     typedefsLoc: '../types/augment/all/defs.json'
 mappings:
   # js module that exports the handler functions
-  mappingsModule: mappings/lib/giza
+  mappingsModule: mappings/lib
   # additinal libraries the processor loads
   # typically it is a module with event and extrinsic types generated by hydra-typegen
   imports:
     - mappings/lib/generated/types
   eventHandlers:
-    # TODO: Sumer mappings
-    # # membership
-    # - event: members.MemberRegistered
-    #   handler: members_MemberRegistered(DatabaseManager, SubstrateEvent)
-    # - event: members.MemberUpdatedAboutText
-    #   handler: members_MemberUpdatedAboutText(DatabaseManager, SubstrateEvent)
-    # - event: members.MemberUpdatedAvatar
-    #   handler: members_MemberUpdatedAvatar(DatabaseManager, SubstrateEvent)
-    # - event: members.MemberUpdatedHandle
-    #   handler: members_MemberUpdatedHandle(DatabaseManager, SubstrateEvent)
-    # - event: members.MemberSetRootAccount
-    #   handler: members_MemberSetRootAccount(DatabaseManager, SubstrateEvent)
-    # - event: members.MemberSetControllerAccount
-    #   handler: members_MemberSetControllerAccount(DatabaseManager, SubstrateEvent)
-
-    # # content directory
-    # - event: content.CuratorGroupCreated
-    #   handler: content_CuratorGroupCreated(DatabaseManager, SubstrateEvent)
-    # - event: content.CuratorGroupStatusSet
-    #   handler: content_CuratorGroupStatusSet(DatabaseManager, SubstrateEvent)
-    # - event: content.CuratorAdded
-    #   handler: content_CuratorAdded(DatabaseManager, SubstrateEvent)
-    # - event: content.CuratorRemoved
-    #   handler: content_CuratorRemoved(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelCreated
-    #   handler: content_ChannelCreated(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelUpdated
-    #   handler: content_ChannelUpdated(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelAssetsRemoved
-    #   handler: content_ChannelAssetsRemoved(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelCensorshipStatusUpdated
-    #   handler: content_ChannelCensorshipStatusUpdated(DatabaseManager, SubstrateEvent)
-    # # these events are defined in runtime but never calles (at the time of writing)
-    # #- event: content.ChannelOwnershipTransferRequested
-    # #  handler: content_ChannelOwnershipTransferRequested(DatabaseManager, SubstrateEvent)
-    # #- event: content.ChannelOwnershipTransferRequestWithdrawn
-    # #  handler: content_ChannelOwnershipTransferRequestWithdrawn(DatabaseManager, SubstrateEvent)
-    # #- event: content.ChannelOwnershipTransferred
-    # #  handler: content_ChannelOwnershipTransferred(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelCategoryCreated
-    #   handler: content_ChannelCategoryCreated(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelCategoryUpdated
-    #   handler: content_ChannelCategoryUpdated(DatabaseManager, SubstrateEvent)
-    # - event: content.ChannelCategoryDeleted
-    #   handler: content_ChannelCategoryDeleted(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoCategoryCreated
-    #   handler: content_VideoCategoryCreated(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoCategoryUpdated
-    #   handler: content_VideoCategoryUpdated(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoCategoryDeleted
-    #   handler: content_VideoCategoryDeleted(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoCreated
-    #   handler: content_VideoCreated(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoUpdated
-    #   handler: content_VideoUpdated(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoDeleted
-    #   handler: content_VideoDeleted(DatabaseManager, SubstrateEvent)
-    # - event: content.VideoCensorshipStatusUpdated
-    #   handler: content_VideoCensorshipStatusUpdated(DatabaseManager, SubstrateEvent)
-    # - event: content.FeaturedVideosSet
-    #   handler: content_FeaturedVideosSet(DatabaseManager, SubstrateEvent)
+    # membership
+    - event: members.MemberRegistered
+      handler: members_MemberRegistered
+    - event: members.MemberUpdatedAboutText
+      handler: members_MemberUpdatedAboutText
+    - event: members.MemberUpdatedAvatar
+      handler: members_MemberUpdatedAvatar
+    - event: members.MemberUpdatedHandle
+      handler: members_MemberUpdatedHandle
+    - event: members.MemberSetRootAccount
+      handler: members_MemberSetRootAccount
+    - event: members.MemberSetControllerAccount
+      handler: members_MemberSetControllerAccount
 
-    # # storage
-    # - event: dataDirectory.ContentAdded
-    #   handler: dataDirectory_ContentAdded(DatabaseManager, SubstrateEvent)
-    # - event: dataDirectory.ContentRemoved
-    #   handler: dataDirectory_ContentRemoved(DatabaseManager, SubstrateEvent)
-    # - event: dataDirectory.ContentAccepted
-    #   handler: dataDirectory_ContentAccepted(DatabaseManager, SubstrateEvent)
-    # # not handled at the moment
-    # #- event: dataDirectory.ContentUploadingStatusUpdated
-    # #  handler: data_directory_ContentUploadingStatusUpdated(DatabaseManager, SubstrateEvent)
+    # content directory
+    - event: content.CuratorGroupCreated
+      handler: content_CuratorGroupCreated
+    - event: content.CuratorGroupStatusSet
+      handler: content_CuratorGroupStatusSet
+    - event: content.CuratorAdded
+      handler: content_CuratorAdded
+    - event: content.CuratorRemoved
+      handler: content_CuratorRemoved
+    - event: content.ChannelCreated
+      handler: content_ChannelCreated
+    - event: content.ChannelUpdated
+      handler: content_ChannelUpdated
+    - event: content.ChannelAssetsRemoved
+      handler: content_ChannelAssetsRemoved
+    - event: content.ChannelCensorshipStatusUpdated
+      handler: content_ChannelCensorshipStatusUpdated
+    # these events are defined in runtime but never emitted (at the time of writing)
+    #- event: content.ChannelOwnershipTransferRequested
+    #  handler: content_ChannelOwnershipTransferRequested
+    #- event: content.ChannelOwnershipTransferRequestWithdrawn
+    #  handler: content_ChannelOwnershipTransferRequestWithdrawn
+    #- event: content.ChannelOwnershipTransferred
+    #  handler: content_ChannelOwnershipTransferred
+    - event: content.ChannelCategoryCreated
+      handler: content_ChannelCategoryCreated
+    - event: content.ChannelCategoryUpdated
+      handler: content_ChannelCategoryUpdated
+    - event: content.ChannelCategoryDeleted
+      handler: content_ChannelCategoryDeleted
+    - event: content.VideoCategoryCreated
+      handler: content_VideoCategoryCreated
+    - event: content.VideoCategoryUpdated
+      handler: content_VideoCategoryUpdated
+    - event: content.VideoCategoryDeleted
+      handler: content_VideoCategoryDeleted
+    - event: content.VideoCreated
+      handler: content_VideoCreated
+    - event: content.VideoUpdated
+      handler: content_VideoUpdated
+    - event: content.VideoDeleted
+      handler: content_VideoDeleted
+    - event: content.VideoCensorshipStatusUpdated
+      handler: content_VideoCensorshipStatusUpdated
+    - event: content.FeaturedVideosSet
+      handler: content_FeaturedVideosSet
 
-    # # working groups
-    # ## storage - workers
-    # - event: storageWorkingGroup.WorkerStorageUpdated
-    #   handler: storageWorkingGroup_WorkerStorageUpdated(DatabaseManager, SubstrateEvent)
-    # - event: storageWorkingGroup.OpeningFilled
-    #   handler: storageWorkingGroup_OpeningFilled(DatabaseManager, SubstrateEvent)
-    # - event: storageWorkingGroup.TerminatedWorker
-    #   handler: storageWorkingGroup_TerminatedWorker(DatabaseManager, SubstrateEvent)
-    # - event: storageWorkingGroup.WorkerExited
-    #   handler: storageWorkingGroup_WorkerExited(DatabaseManager, SubstrateEvent)
+    # working groups
+    ## storage - workers
+    - event: storageWorkingGroup.WorkerStorageUpdated
+      handler: workingGroup_WorkerStorageUpdated
+    - event: storageWorkingGroup.OpeningFilled
+      handler: workingGroup_OpeningFilled
+    - event: storageWorkingGroup.TerminatedWorker
+      handler: workingGroup_TerminatedWorker
+    - event: storageWorkingGroup.WorkerExited
+      handler: workingGroup_WorkerExited
 
-    # ## storage - leader
-    # - event: storageWorkingGroup.TerminatedLeader
-    #   handler: storageWorkingGroup_TerminatedLeader(DatabaseManager, SubstrateEvent)
+    ## storage - leader
+    - event: storageWorkingGroup.TerminatedLeader
+      handler: workingGroup_TerminatedLeader
 
-    # ## gateway - workers
-    # - event: gatewayWorkingGroup.WorkerStorageUpdated
-    #   handler: gatewayWorkingGroup_WorkerStorageUpdated(DatabaseManager, SubstrateEvent)
-    # - event: gatewayWorkingGroup.OpeningFilled
-    #   handler: gatewayWorkingGroup_OpeningFilled(DatabaseManager, SubstrateEvent)
-    # - event: gatewayWorkingGroup.TerminatedWorker
-    #   handler: gatewayWorkingGroup_TerminatedWorker(DatabaseManager, SubstrateEvent)
-    # - event: gatewayWorkingGroup.WorkerExited
-    #   handler: gatewayWorkingGroup_WorkerExited(DatabaseManager, SubstrateEvent)
+    ## gateway - workers
+    - event: gatewayWorkingGroup.WorkerStorageUpdated
+      handler: workingGroup_WorkerStorageUpdated
+    - event: gatewayWorkingGroup.OpeningFilled
+      handler: workingGroup_OpeningFilled
+    - event: gatewayWorkingGroup.TerminatedWorker
+      handler: workingGroup_TerminatedWorker
+    - event: gatewayWorkingGroup.WorkerExited
+      handler: workingGroup_WorkerExited
 
-    # ## gateway - leader
-    # - event: gatewayWorkingGroup.TerminatedLeader
-    #   handler: gatewayWorkingGroup_TerminatedLeader(DatabaseManager, SubstrateEvent)
+    ## gateway - leader
+    - event: gatewayWorkingGroup.TerminatedLeader
+      handler: workingGroup_TerminatedLeader
 
     # storage v2
     - event: storage.StorageBucketCreated
@@ -315,8 +247,6 @@ mappings:
       handler: storage_VoucherChanged
     - event: storage.StorageBucketDeleted
       handler: storage_StorageBucketDeleted
-    - event: storage.NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated
-      handler: storage_NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated
     - event: storage.DistributionBucketFamilyCreated
       handler: storage_DistributionBucketFamilyCreated
     - event: storage.DistributionBucketFamilyDeleted
@@ -333,8 +263,6 @@ mappings:
       handler: storage_DistributionBucketsPerBagLimitUpdated
     - event: storage.DistributionBucketModeUpdated
       handler: storage_DistributionBucketModeUpdated
-    - event: storage.FamiliesInDynamicBagCreationPolicyUpdated
-      handler: storage_FamiliesInDynamicBagCreationPolicyUpdated
     - event: storage.DistributionBucketOperatorInvited
       handler: storage_DistributionBucketOperatorInvited
     - event: storage.DistributionBucketInvitationCancelled

+ 1 - 0
query-node/mappings/.eslintignore

@@ -1 +1,2 @@
 lib/
+generated

+ 1 - 0
query-node/mappings/.prettierignore

@@ -1 +1,2 @@
 lib/
+generated

+ 96 - 98
query-node/mappings/sumer/common.ts → query-node/mappings/common.ts

@@ -1,16 +1,34 @@
-import { SubstrateEvent, SubstrateExtrinsic, ExtrinsicArg } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { u64, Bytes } from '@polkadot/types/primitive'
-import { fixBlockTimestamp } from './eventFix'
+import { DatabaseManager, SubstrateEvent, SubstrateExtrinsic, ExtrinsicArg } from '@joystream/hydra-common'
+import { Bytes } from '@polkadot/types'
+import { Network } from 'query-node/dist/model'
+import { BaseModel } from '@joystream/warthog'
+import { metaToObject } from '@joystream/metadata-protobuf/utils'
+import { AnyMetadataClass, DecodedMetadataObject } from '@joystream/metadata-protobuf/types'
+
+export const CURRENT_NETWORK = Network.GIZA
+/*
+  Simple logger enabling error and informational reporting.
 
-// Asset
-import { DataObjectOwner, DataObject, LiaisonJudgement, Network, NextEntityId } from 'query-node'
-import { ContentParameters } from '@joystream/types/augment'
+  FIXME: `Logger` class will not be needed in the future when Hydra v3 will be released.
+  Hydra will provide logger instance and relevant code using `Logger` should be refactored.
+*/
+class Logger {
+  /*
+    Log significant event.
+  */
+  info(message: string, data?: unknown) {
+    console.log(message, data)
+  }
 
-import { ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
-import { registry } from '@joystream/types'
+  /*
+    Log significant error.
+  */
+  error(message: string, data?: unknown) {
+    console.error(message, data)
+  }
+}
 
-const currentNetwork = Network.BABYLON
+export const logger = new Logger()
 
 /*
   Reports that insurmountable inconsistent state has been encountered and throws an exception.
@@ -21,71 +39,32 @@ export function inconsistentState(extraInfo: string, data?: unknown): never {
   // log error
   logger.error(errorMessage, data)
 
-  throw new Error(errorMessage)
+  throw errorMessage
 }
 
 /*
-  Reports that metadata inserted by the user are not entirely valid, but the problem can be overcome.
+  Reports that insurmountable unexpected data has been encountered and throws an exception.
 */
-export function invalidMetadata(extraInfo: string, data?: unknown): void {
-  const errorMessage = 'Invalid metadata: ' + extraInfo
+export function unexpectedData(extraInfo: string, data?: unknown): never {
+  const errorMessage = 'Unexpected data: ' + extraInfo
 
   // log error
-  logger.info(errorMessage, data)
-}
-
-/*
-  Creates a predictable and unique ID for the given content.
-*/
-export async function getNextId(db: DatabaseManager): Promise<string> {
-  // load or create record
-  const existingRecord = (await db.get(NextEntityId, {})) || new NextEntityId({ id: '0', nextId: 1 })
-
-  // remember id
-  const entityId = existingRecord.nextId
-
-  // increment id
-  existingRecord.nextId = existingRecord.nextId + 1
-
-  // save record
-  await db.save<NextEntityId>(existingRecord)
+  logger.error(errorMessage, data)
 
-  return entityId.toString()
+  throw errorMessage
 }
 
 /*
-  Prepares data object from content parameters.
+  Reports that metadata inserted by the user are not entirely valid, but the problem can be overcome.
 */
-export async function prepareDataObject(
-  db: DatabaseManager,
-  contentParameters: ContentParameters,
-  event: SubstrateEvent,
-  owner: typeof DataObjectOwner
-): Promise<DataObject> {
-  // convert generic content parameters coming from processor to custom Joystream data type
-  const customContentParameters = new Custom_ContentParameters(registry, contentParameters.toJSON() as any)
-
-  const dataObject = new DataObject({
-    id: await getNextId(db),
-    owner,
-    createdInBlock: event.blockNumber,
-    typeId: contentParameters.type_id.toNumber(),
-    size: customContentParameters.size_in_bytes.toNumber(),
-    liaisonJudgement: LiaisonJudgement.PENDING, // judgement is pending at start; liaison id is set when content is accepted/rejected
-    ipfsContentId: convertBytesToString(contentParameters.ipfs_content_id),
-    joystreamContentId: customContentParameters.content_id.encode(),
-
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    createdById: '1',
-    updatedById: '1',
-  })
+export function invalidMetadata(extraInfo: string, data?: unknown): void {
+  const errorMessage = 'Invalid metadata: ' + extraInfo
 
-  return dataObject
+  // log error
+  logger.info(errorMessage, data)
 }
 
-/// ///////////////// Sudo extrinsic calls ///////////////////////////////////////
+/// //////////////// Sudo extrinsic calls ///////////////////////////////////////
 
 // soft-peg interface for typegen-generated `*Call` types
 export interface IGenericExtrinsicObject<T> {
@@ -105,12 +84,13 @@ export interface ISudoCallArgs<T> extends ExtrinsicArg {
 */
 export function extractExtrinsicArgs<DataParams, EventObject extends IGenericExtrinsicObject<DataParams>>(
   rawEvent: SubstrateEvent,
-  callFactory: new (event: SubstrateEvent) => EventObject,
+  callFactoryConstructor: new (event: SubstrateEvent) => EventObject,
 
   // in ideal world this parameter would not be needed, but there is no way to associate parameters
   // used in sudo to extrinsic parameters without it
   argsIndeces: Record<keyof DataParams, number>
 ): EventObject['args'] {
+  const CallFactory = callFactoryConstructor
   // this is equal to DataParams but only this notation works properly
   // escape when extrinsic info is not available
   if (!rawEvent.extrinsic) {
@@ -119,8 +99,7 @@ export function extractExtrinsicArgs<DataParams, EventObject extends IGenericExt
 
   // regural extrinsic call?
   if (rawEvent.extrinsic.section !== 'sudo') {
-    // eslint-disable-next-line new-cap
-    return new callFactory(rawEvent).args
+    return new CallFactory(rawEvent).args
   }
 
   // sudo extrinsic call
@@ -150,8 +129,7 @@ export function extractExtrinsicArgs<DataParams, EventObject extends IGenericExt
   } as SubstrateEvent
 
   // create event object and extract processed args
-  // eslint-disable-next-line new-cap
-  const finalArgs = new callFactory(partialEvent).args
+  const finalArgs = new CallFactory(partialEvent).args
 
   return finalArgs
 }
@@ -183,45 +161,65 @@ export function extractSudoCallParameters<DataParams>(rawEvent: SubstrateEvent):
   return callArgs
 }
 
-/// ///////////////// Logger /////////////////////////////////////////////////////
-
-/*
-  Simple logger enabling error and informational reporting.
-
-  `Logger` class will not be needed in the future when Hydra v3 will be released.
-  Hydra will provide logger instance and relevant code using `Logger` should be refactored.
-*/
-class Logger {
-  /*
-    Log significant event.
-  */
-  info(message: string, data?: unknown) {
-    console.log(message, data)
+export function deserializeMetadata<T>(
+  metadataType: AnyMetadataClass<T>,
+  metadataBytes: Bytes
+): DecodedMetadataObject<T> | null {
+  try {
+    return metaToObject(metadataType, metadataType.decode(metadataBytes.toU8a(true)))
+  } catch (e) {
+    invalidMetadata(`Cannot deserialize ${metadataType.name}! Provided bytes: (${metadataBytes.toHex()})`)
+    return null
   }
+}
 
-  /*
-    Log significant error.
-  */
-  error(message: string, data?: unknown) {
-    console.error(message, data)
-  }
+export function bytesToString(b: Bytes): string {
+  return (
+    Buffer.from(b.toU8a(true))
+      .toString()
+      // eslint-disable-next-line no-control-regex
+      .replace(/\u0000/g, '')
+  )
 }
 
-export const logger = new Logger()
+export function perpareString(s: string): string {
+  // eslint-disable-next-line no-control-regex
+  return s.replace(/\u0000/g, '')
+}
 
-/*
-  Helper for converting Bytes type to string
-*/
-export function convertBytesToString(b: Bytes | null): string {
-  if (!b) {
-    return ''
-  }
+export function hasValuesForProperties<
+  T extends Record<string, unknown>,
+  P extends keyof T & string,
+  PA extends readonly P[]
+>(obj: T, props: PA): obj is T & { [K in PA[number]]: NonNullable<K> } {
+  props.forEach((p) => {
+    if (obj[p] === null || obj[p] === undefined) {
+      return false
+    }
+  })
+  return true
+}
 
-  const text = Buffer.from(b.toU8a(true)).toString()
+type EntityClass<T extends BaseModel> = {
+  new (): T
+  name: string
+}
 
-  // prevent utf-8 null character
-  // eslint-disable-next-line no-control-regex
-  const result = text.replace(/\u0000/g, '')
+type RelationsArr<T extends BaseModel> = Exclude<
+  keyof T & string,
+  { [K in keyof T]: T[K] extends BaseModel | undefined ? '' : T[K] extends BaseModel[] | undefined ? '' : K }[keyof T]
+>[]
+
+export async function getById<T extends BaseModel>(
+  store: DatabaseManager,
+  entityClass: EntityClass<T>,
+  id: string,
+  relations?: RelationsArr<T>
+): Promise<T> {
+  const result = await store.get(entityClass, { where: { id }, relations })
+  if (!result) {
+    throw new Error(`Expected ${entityClass.name} not found by ID: ${id}`)
+  }
 
   return result
 }

+ 230 - 0
query-node/mappings/content/channel.ts

@@ -0,0 +1,230 @@
+/*
+eslint-disable @typescript-eslint/naming-convention
+*/
+import { EventContext, StoreContext } from '@joystream/hydra-common'
+import { AccountId } from '@polkadot/types/interfaces'
+import { Option } from '@polkadot/types/codec'
+import { Content } from '../generated/types'
+import { convertContentActorToChannelOwner, processChannelMetadata } from './utils'
+import { AssetNone, Channel, ChannelCategory } from 'query-node/dist/model'
+import { deserializeMetadata, inconsistentState, logger } from '../common'
+import { ChannelCategoryMetadata, ChannelMetadata } from '@joystream/metadata-protobuf'
+import { integrateMeta } from '@joystream/metadata-protobuf/utils'
+
+export async function content_ChannelCreated(ctx: EventContext & StoreContext): Promise<void> {
+  const { store, event } = ctx
+  // read event data
+  const [contentActor, channelId, , channelCreationParameters] = new Content.ChannelCreatedEvent(event).params
+
+  // create entity
+  const channel = new Channel({
+    // main data
+    id: channelId.toString(),
+    isCensored: false,
+    videos: [],
+    createdInBlock: event.blockNumber,
+    // assets
+    coverPhoto: new AssetNone(),
+    avatarPhoto: new AssetNone(),
+    // fill in auto-generated fields
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+    // prepare channel owner (handles fields `ownerMember` and `ownerCuratorGroup`)
+    ...(await convertContentActorToChannelOwner(store, contentActor)),
+  })
+
+  // deserialize & process metadata
+  const metadata = deserializeMetadata(ChannelMetadata, channelCreationParameters.meta) || {}
+  await processChannelMetadata(ctx, channel, metadata, channelCreationParameters.assets)
+
+  // save entity
+  await store.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel has been created', { id: channel.id })
+}
+
+export async function content_ChannelUpdated(ctx: EventContext & StoreContext): Promise<void> {
+  const { store, event } = ctx
+  // read event data
+  const [, channelId, , channelUpdateParameters] = new Content.ChannelUpdatedEvent(event).params
+
+  // load channel
+  const channel = await store.get(Channel, { where: { id: channelId.toString() } })
+
+  // ensure channel exists
+  if (!channel) {
+    return inconsistentState('Non-existing channel update requested', channelId)
+  }
+
+  // prepare changed metadata
+  const newMetadataBytes = channelUpdateParameters.new_meta.unwrapOr(null)
+
+  //  update metadata if it was changed
+  if (newMetadataBytes) {
+    const newMetadata = deserializeMetadata(ChannelMetadata, newMetadataBytes) || {}
+    await processChannelMetadata(ctx, channel, newMetadata, channelUpdateParameters.assets.unwrapOr([]))
+  }
+
+  // prepare changed reward account
+  const newRewardAccount = channelUpdateParameters.reward_account.unwrapOr(null)
+
+  // reward account change happened?
+  if (newRewardAccount) {
+    // this will change the `channel`!
+    handleChannelRewardAccountChange(channel, newRewardAccount)
+  }
+
+  // set last update time
+  channel.updatedAt = new Date(event.blockTimestamp)
+
+  // save channel
+  await store.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel has been updated', { id: channel.id })
+}
+
+export async function content_ChannelAssetsRemoved({ store, event }: EventContext & StoreContext): Promise<void> {
+  // TODO: Storage v2 integration
+  // // read event data
+  // const [, , contentIds] = new Content.ChannelAssetsRemovedEvent(event).params
+  // const assets = await store.getMany(StorageDataObject, {
+  //   where: {
+  //     id: In(contentIds.toArray().map((item) => item.toString())),
+  //   },
+  // })
+  // // delete assets
+  // await Promise.all(assets.map((a) => store.remove<StorageDataObject>(a)))
+  // // emit log event
+  // logger.info('Channel assets have been removed', { ids: contentIds })
+}
+
+export async function content_ChannelCensorshipStatusUpdated({
+  store,
+  event,
+}: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, channelId, isCensored] = new Content.ChannelCensorshipStatusUpdatedEvent(event).params
+
+  // load event
+  const channel = await store.get(Channel, { where: { id: channelId.toString() } })
+
+  // ensure channel exists
+  if (!channel) {
+    return inconsistentState('Non-existing channel censoring requested', channelId)
+  }
+
+  // update channel
+  channel.isCensored = isCensored.isTrue
+
+  // set last update time
+  channel.updatedAt = new Date(event.blockTimestamp)
+
+  // save channel
+  await store.save<Channel>(channel)
+
+  // emit log event
+  logger.info('Channel censorship status has been updated', { id: channelId, isCensored: isCensored.isTrue })
+}
+
+/// //////////////// ChannelCategory ////////////////////////////////////////////
+
+export async function content_ChannelCategoryCreated({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [channelCategoryId, , channelCategoryCreationParameters] = new Content.ChannelCategoryCreatedEvent(event).params
+
+  // read metadata
+  const metadata = deserializeMetadata(ChannelCategoryMetadata, channelCategoryCreationParameters.meta) || {}
+
+  // create new channel category
+  const channelCategory = new ChannelCategory({
+    // main data
+    id: channelCategoryId.toString(),
+    channels: [],
+    createdInBlock: event.blockNumber,
+
+    // fill in auto-generated fields
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+  })
+  integrateMeta(channelCategory, metadata, ['name'])
+
+  // save channel
+  await store.save<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been created', { id: channelCategory.id })
+}
+
+export async function content_ChannelCategoryUpdated({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, channelCategoryId, channelCategoryUpdateParameters] = new Content.ChannelCategoryUpdatedEvent(event).params
+
+  // load channel category
+  const channelCategory = await store.get(ChannelCategory, {
+    where: {
+      id: channelCategoryId.toString(),
+    },
+  })
+
+  // ensure channel exists
+  if (!channelCategory) {
+    return inconsistentState('Non-existing channel category update requested', channelCategoryId)
+  }
+
+  // read metadata
+  const newMeta = deserializeMetadata(ChannelCategoryMetadata, channelCategoryUpdateParameters.new_meta) || {}
+  integrateMeta(channelCategory, newMeta, ['name'])
+
+  // set last update time
+  channelCategory.updatedAt = new Date(event.blockTimestamp)
+
+  // save channel category
+  await store.save<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been updated', { id: channelCategory.id })
+}
+
+export async function content_ChannelCategoryDeleted({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, channelCategoryId] = new Content.ChannelCategoryDeletedEvent(event).params
+
+  // load channel category
+  const channelCategory = await store.get(ChannelCategory, {
+    where: {
+      id: channelCategoryId.toString(),
+    },
+  })
+
+  // ensure channel category exists
+  if (!channelCategory) {
+    return inconsistentState('Non-existing channel category deletion requested', channelCategoryId)
+  }
+
+  // delete channel category
+  await store.remove<ChannelCategory>(channelCategory)
+
+  // emit log event
+  logger.info('Channel category has been deleted', { id: channelCategory.id })
+}
+
+/// //////////////// Helpers ////////////////////////////////////////////////////
+
+function handleChannelRewardAccountChange(
+  channel: Channel, // will be modified inside of the function!
+  reward_account: Option<AccountId>
+) {
+  const rewardAccount = reward_account.unwrapOr(null)
+
+  // new different reward account set?
+  if (rewardAccount) {
+    channel.rewardAccount = rewardAccount.toString()
+    return
+  }
+
+  // reward account removed
+
+  channel.rewardAccount = undefined // plan deletion (will have effect when saved to db)
+}

+ 25 - 26
query-node/mappings/sumer/content/curatorGroup.ts → query-node/mappings/content/curatorGroup.ts

@@ -1,16 +1,15 @@
-import { fixBlockTimestamp } from '../eventFix'
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+/*
+eslint-disable @typescript-eslint/naming-convention
+*/
+import { EventContext, StoreContext } from '@joystream/hydra-common'
 import { FindConditions } from 'typeorm'
-
-import { CuratorGroup } from 'query-node'
-import { Content } from '../../../generated/types'
-
+import { CuratorGroup } from 'query-node/dist/model'
+import { Content } from '../generated/types'
 import { inconsistentState, logger } from '../common'
 
-export async function content_CuratorGroupCreated(db: DatabaseManager, event: SubstrateEvent) {
+export async function content_CuratorGroupCreated({ store, event }: EventContext & StoreContext): Promise<void> {
   // read event data
-  const { curatorGroupId } = new Content.CuratorGroupCreatedEvent(event).data
+  const [curatorGroupId] = new Content.CuratorGroupCreatedEvent(event).params
 
   // create new curator group
   const curatorGroup = new CuratorGroup({
@@ -20,23 +19,23 @@ export async function content_CuratorGroupCreated(db: DatabaseManager, event: Su
     isActive: false, // runtime creates inactive curator groups by default
 
     // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
   })
 
   // save curator group
-  await db.save<CuratorGroup>(curatorGroup)
+  await store.save<CuratorGroup>(curatorGroup)
 
   // emit log event
   logger.info('Curator group has been created', { id: curatorGroupId })
 }
 
-export async function content_CuratorGroupStatusSet(db: DatabaseManager, event: SubstrateEvent) {
+export async function content_CuratorGroupStatusSet({ store, event }: EventContext & StoreContext): Promise<void> {
   // read event data
-  const { curatorGroupId, bool: isActive } = new Content.CuratorGroupStatusSetEvent(event).data
+  const [curatorGroupId, isActive] = new Content.CuratorGroupStatusSetEvent(event).params
 
   // load curator group
-  const curatorGroup = await db.get(CuratorGroup, {
+  const curatorGroup = await store.get(CuratorGroup, {
     where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>,
   })
 
@@ -49,21 +48,21 @@ export async function content_CuratorGroupStatusSet(db: DatabaseManager, event:
   curatorGroup.isActive = isActive.isTrue
 
   // set last update time
-  curatorGroup.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  curatorGroup.updatedAt = new Date(event.blockTimestamp)
 
   // save curator group
-  await db.save<CuratorGroup>(curatorGroup)
+  await store.save<CuratorGroup>(curatorGroup)
 
   // emit log event
   logger.info('Curator group status has been set', { id: curatorGroupId, isActive })
 }
 
-export async function content_CuratorAdded(db: DatabaseManager, event: SubstrateEvent) {
+export async function content_CuratorAdded({ store, event }: EventContext & StoreContext): Promise<void> {
   // read event data
-  const { curatorGroupId, curatorId } = new Content.CuratorAddedEvent(event).data
+  const [curatorGroupId, curatorId] = new Content.CuratorAddedEvent(event).params
 
   // load curator group
-  const curatorGroup = await db.get(CuratorGroup, {
+  const curatorGroup = await store.get(CuratorGroup, {
     where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>,
   })
 
@@ -76,21 +75,21 @@ export async function content_CuratorAdded(db: DatabaseManager, event: Substrate
   curatorGroup.curatorIds.push(curatorId.toNumber())
 
   // set last update time
-  curatorGroup.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  curatorGroup.updatedAt = new Date(event.blockTimestamp)
 
   // save curator group
-  await db.save<CuratorGroup>(curatorGroup)
+  await store.save<CuratorGroup>(curatorGroup)
 
   // emit log event
   logger.info('Curator has been added to curator group', { id: curatorGroupId, curatorId })
 }
 
-export async function content_CuratorRemoved(db: DatabaseManager, event: SubstrateEvent) {
+export async function content_CuratorRemoved({ store, event }: EventContext & StoreContext): Promise<void> {
   // read event data
-  const { curatorGroupId, curatorId } = new Content.CuratorAddedEvent(event).data
+  const [curatorGroupId, curatorId] = new Content.CuratorAddedEvent(event).params
 
   // load curator group
-  const curatorGroup = await db.get(CuratorGroup, {
+  const curatorGroup = await store.get(CuratorGroup, {
     where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>,
   })
 
@@ -110,7 +109,7 @@ export async function content_CuratorRemoved(db: DatabaseManager, event: Substra
   curatorGroup.curatorIds.splice(curatorIndex, 1)
 
   // save curator group
-  await db.save<CuratorGroup>(curatorGroup)
+  await store.save<CuratorGroup>(curatorGroup)
 
   // emit log event
   logger.info('Curator has been removed from curator group', { id: curatorGroupId, curatorId })

+ 0 - 0
query-node/mappings/sumer/content/index.ts → query-node/mappings/content/index.ts


+ 466 - 0
query-node/mappings/content/utils.ts

@@ -0,0 +1,466 @@
+import { DatabaseManager, EventContext, StoreContext } from '@joystream/hydra-common'
+import { FindConditions } from 'typeorm'
+import {
+  IVideoMetadata,
+  IPublishedBeforeJoystream,
+  ILicense,
+  IMediaType,
+  IChannelMetadata,
+} from '@joystream/metadata-protobuf'
+import { integrateMeta, isSet, isValidLanguageCode } from '@joystream/metadata-protobuf/utils'
+import { invalidMetadata, inconsistentState, logger } from '../common'
+import {
+  // primary entities
+  CuratorGroup,
+  Channel,
+  Video,
+  VideoCategory,
+  // secondary entities
+  Language,
+  License,
+  VideoMediaMetadata,
+  // asset
+  Asset,
+  Membership,
+  VideoMediaEncoding,
+  ChannelCategory,
+  AssetNone,
+} from 'query-node/dist/model'
+// Joystream types
+import { NewAsset, ContentActor } from '@joystream/types/augment'
+import { DecodedMetadataObject } from '@joystream/metadata-protobuf/types'
+import BN from 'bn.js'
+
+export async function processChannelMetadata(
+  ctx: EventContext & StoreContext,
+  channel: Channel,
+  meta: DecodedMetadataObject<IChannelMetadata>,
+  assets: NewAsset[]
+): Promise<Channel> {
+  // TODO: Assets processing (Storage v2)
+  // const assetsOwner = new DataObjectOwnerChannel()
+  // assetsOwner.channelId = channel.id
+
+  // const processedAssets = await Promise.all(assets.map((asset) => processNewAsset(ctx, asset, assetsOwner)))
+
+  integrateMeta(channel, meta, ['title', 'description', 'isPublic'])
+
+  // prepare channel category if needed
+  if (isSet(meta.category)) {
+    channel.category = await processChannelCategory(ctx, channel.category, parseInt(meta.category))
+  }
+
+  channel.coverPhoto = new AssetNone()
+  channel.avatarPhoto = new AssetNone()
+  // // prepare cover photo asset if needed
+  // if (isSet(meta.coverPhoto)) {
+  //   const asset = findAssetByIndex(processedAssets, meta.coverPhoto, 'channel cover photo')
+  //   if (asset) {
+  //     channel.coverPhoto = asset
+  //   }
+  // }
+
+  // // prepare avatar photo asset if needed
+  // if (isSet(meta.avatarPhoto)) {
+  //   const asset = findAssetByIndex(processedAssets, meta.avatarPhoto, 'channel avatar photo')
+  //   if (asset) {
+  //     channel.avatarPhoto = asset
+  //   }
+  // }
+
+  // prepare language if needed
+  if (isSet(meta.language)) {
+    channel.language = await processLanguage(ctx, channel.language, meta.language)
+  }
+
+  return channel
+}
+
+export async function processVideoMetadata(
+  ctx: EventContext & StoreContext,
+  channel: Channel,
+  video: Video,
+  meta: DecodedMetadataObject<IVideoMetadata>,
+  assets: NewAsset[]
+): Promise<Video> {
+  // TODO: Assets processing (Storage v2)
+  // const assetsOwner = new DataObjectOwnerChannel()
+  // assetsOwner.channelId = channel.id
+
+  // const processedAssets = await Promise.all(assets.map((asset) => processNewAsset(ctx, asset, assetsOwner)))
+
+  integrateMeta(video, meta, ['title', 'description', 'duration', 'hasMarketing', 'isExplicit', 'isPublic'])
+
+  // prepare video category if needed
+  if (meta.category) {
+    video.category = await processVideoCategory(ctx, video.category, parseInt(meta.category))
+  }
+
+  // prepare media meta information if needed
+  if (isSet(meta.mediaType) || isSet(meta.mediaPixelWidth) || isSet(meta.mediaPixelHeight)) {
+    // prepare video file size if poosible
+    const videoSize = 0 // TODO: extractVideoSize(assets, meta.video)
+    video.mediaMetadata = await processVideoMediaMetadata(ctx, video.mediaMetadata, meta, videoSize)
+  }
+
+  // prepare license if needed
+  if (isSet(meta.license)) {
+    await updateVideoLicense(ctx, video, meta.license)
+  }
+
+  video.thumbnailPhoto = new AssetNone()
+  video.media = new AssetNone()
+  // // prepare thumbnail photo asset if needed
+  // if (isSet(meta.thumbnailPhoto)) {
+  //   const asset = findAssetByIndex(processedAssets, meta.thumbnailPhoto, 'thumbnail photo')
+  //   if (asset) {
+  //     video.thumbnailPhoto = asset
+  //   }
+  // }
+
+  // // prepare video asset if needed
+  // if (isSet(meta.video)) {
+  //   const asset = findAssetByIndex(processedAssets, meta.video, 'video')
+  //   if (asset) {
+  //     video.media = asset
+  //   }
+  // }
+
+  // prepare language if needed
+  if (isSet(meta.language)) {
+    video.language = await processLanguage(ctx, video.language, meta.language)
+  }
+
+  if (isSet(meta.publishedBeforeJoystream)) {
+    video.publishedBeforeJoystream = processPublishedBeforeJoystream(
+      ctx,
+      video.publishedBeforeJoystream,
+      meta.publishedBeforeJoystream
+    )
+  }
+
+  return video
+}
+
+function findAssetByIndex(assets: typeof Asset[], index: number, name?: string): typeof Asset | null {
+  if (assets[index]) {
+    return assets[index]
+  } else {
+    invalidMetadata(`Invalid${name ? ' ' + name : ''} asset index`, {
+      numberOfAssets: assets.length,
+      requestedAssetIndex: index,
+    })
+
+    return null
+  }
+}
+
+async function processVideoMediaEncoding(
+  { store, event }: StoreContext & EventContext,
+  existingVideoMediaEncoding: VideoMediaEncoding | undefined,
+  metadata: DecodedMetadataObject<IMediaType>
+): Promise<VideoMediaEncoding> {
+  const encoding =
+    existingVideoMediaEncoding ||
+    new VideoMediaEncoding({
+      createdAt: new Date(event.blockTimestamp),
+      createdById: '1',
+      updatedById: '1',
+    })
+  // integrate media encoding-related data
+  integrateMeta(encoding, metadata, ['codecName', 'container', 'mimeMediaType'])
+  encoding.updatedAt = new Date(event.blockTimestamp)
+  await store.save<VideoMediaEncoding>(encoding)
+
+  return encoding
+}
+
+async function processVideoMediaMetadata(
+  ctx: StoreContext & EventContext,
+  existingVideoMedia: VideoMediaMetadata | undefined,
+  metadata: DecodedMetadataObject<IVideoMetadata>,
+  videoSize: number | undefined
+): Promise<VideoMediaMetadata> {
+  const { store, event } = ctx
+  const videoMedia =
+    existingVideoMedia ||
+    new VideoMediaMetadata({
+      createdInBlock: event.blockNumber,
+      createdAt: new Date(event.blockTimestamp),
+      createdById: '1',
+      updatedById: '1',
+    })
+
+  // integrate media-related data
+  const mediaMetadata = {
+    size: isSet(videoSize) ? new BN(videoSize.toString()) : undefined,
+    pixelWidth: metadata.mediaPixelWidth,
+    pixelHeight: metadata.mediaPixelHeight,
+  }
+  integrateMeta(videoMedia, mediaMetadata, ['pixelWidth', 'pixelHeight', 'size'])
+  videoMedia.updatedAt = new Date(event.blockTimestamp)
+  videoMedia.encoding = await processVideoMediaEncoding(ctx, videoMedia.encoding, metadata.mediaType || {})
+  await store.save<VideoMediaMetadata>(videoMedia)
+
+  return videoMedia
+}
+
+export async function convertContentActorToChannelOwner(
+  store: DatabaseManager,
+  contentActor: ContentActor
+): Promise<{
+  ownerMember?: Membership
+  ownerCuratorGroup?: CuratorGroup
+}> {
+  if (contentActor.isMember) {
+    const memberId = contentActor.asMember.toNumber()
+    const member = await store.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+
+    // ensure member exists
+    if (!member) {
+      return inconsistentState(`Actor is non-existing member`, memberId)
+    }
+
+    return {
+      ownerMember: member,
+      ownerCuratorGroup: undefined, // this will clear the field
+    }
+  }
+
+  if (contentActor.isCurator) {
+    const curatorGroupId = contentActor.asCurator[0].toNumber()
+    const curatorGroup = await store.get(CuratorGroup, {
+      where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>,
+    })
+
+    // ensure curator group exists
+    if (!curatorGroup) {
+      return inconsistentState('Actor is non-existing curator group', curatorGroupId)
+    }
+
+    return {
+      ownerMember: undefined, // this will clear the field
+      ownerCuratorGroup: curatorGroup,
+    }
+  }
+
+  // TODO: contentActor.isLead
+
+  logger.error('Not implemented ContentActor type', { contentActor: contentActor.toString() })
+  throw new Error('Not-implemented ContentActor type used')
+}
+
+function processPublishedBeforeJoystream(
+  ctx: EventContext & StoreContext,
+  currentValue: Date | undefined,
+  metadata: DecodedMetadataObject<IPublishedBeforeJoystream>
+): Date | undefined {
+  if (!isSet(metadata)) {
+    return currentValue
+  }
+
+  // Property is beeing unset
+  if (!metadata.isPublished) {
+    return undefined
+  }
+
+  // try to parse timestamp from publish date
+  const timestamp = isSet(metadata.date) ? Date.parse(metadata.date) : NaN
+
+  // ensure date is valid
+  if (isNaN(timestamp)) {
+    invalidMetadata(`Invalid date used for publishedBeforeJoystream`, {
+      timestamp,
+    })
+    return currentValue
+  }
+
+  // set new date
+  return new Date(timestamp)
+}
+
+// TODO: Assets processing (Storage v2)
+// async function processNewAsset(
+//   ctx: EventContext & StoreContext,
+//   asset: NewAsset,
+//   owner: typeof DataObjectOwner
+// ): Promise<typeof Asset> {
+//   if (asset.isUrls) {
+//     const urls = asset.asUrls.toArray().map((url) => url.toString())
+//     const resultAsset = new AssetExternal()
+//     resultAsset.urls = JSON.stringify(urls)
+//     return resultAsset
+//   } else if (asset.isUpload) {
+//     const contentParameters: ContentParameters = asset.asUpload
+//     const dataObject = await createDataObject(ctx, contentParameters, owner)
+
+//     const resultAsset = new AssetJoystreamStorage()
+//     resultAsset.dataObjectId = dataObject.id
+//     return resultAsset
+//   } else {
+//     unexpectedData('Unrecognized asset type', asset.type)
+//   }
+// }
+
+// function extractVideoSize(assets: NewAsset[], assetIndex: number | null | undefined): number | undefined {
+//   // escape if no asset is required
+//   if (!isSet(assetIndex)) {
+//     return undefined
+//   }
+
+//   // ensure asset index is valid
+//   if (assetIndex > assets.length) {
+//     invalidMetadata(`Non-existing asset video size extraction requested`, { assetsProvided: assets.length, assetIndex })
+//     return undefined
+//   }
+
+//   const rawAsset = assets[assetIndex]
+
+//   // escape if asset is describing URLs (can't get size)
+//   if (rawAsset.isUrls) {
+//     return undefined
+//   }
+
+//   // !rawAsset.isUrls && rawAsset.isUpload // asset is in storage
+
+//   // convert generic content parameters coming from processor to custom Joystream data type
+//   const customContentParameters = new Custom_ContentParameters(registry, rawAsset.asUpload.toJSON() as any)
+//   // extract video size
+//   const videoSize = customContentParameters.size_in_bytes.toNumber()
+
+//   return videoSize
+// }
+
+async function processLanguage(
+  ctx: EventContext & StoreContext,
+  currentLanguage: Language | undefined,
+  languageIso: string | undefined
+): Promise<Language | undefined> {
+  const { event, store } = ctx
+
+  if (!isSet(languageIso)) {
+    return currentLanguage
+  }
+
+  // ensure language string is valid
+  if (!isValidLanguageCode(languageIso)) {
+    invalidMetadata(`Invalid language ISO-639-1 provided`, languageIso)
+    return currentLanguage
+  }
+
+  // load language
+  const existingLanguage = await store.get(Language, { where: { iso: languageIso } })
+
+  // return existing language if any
+  if (existingLanguage) {
+    return existingLanguage
+  }
+
+  // create new language
+  const newLanguage = new Language({
+    iso: languageIso,
+    createdInBlock: event.blockNumber,
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+    // TODO: remove these lines after Hydra auto-fills the values when cascading save (remove them on all places)
+    createdById: '1',
+    updatedById: '1',
+  })
+
+  await store.save<Language>(newLanguage)
+
+  return newLanguage
+}
+
+async function updateVideoLicense(
+  ctx: StoreContext & EventContext,
+  video: Video,
+  licenseMetadata: ILicense | null | undefined
+): Promise<void> {
+  const { store, event } = ctx
+
+  if (!isSet(licenseMetadata)) {
+    return
+  }
+
+  const previousLicense = video.license
+  let license: License | null = null
+
+  if (!isLicenseEmpty(licenseMetadata)) {
+    // license is meant to be created/updated
+    license =
+      previousLicense ||
+      new License({
+        createdAt: new Date(event.blockTimestamp),
+        createdById: '1',
+        updatedById: '1',
+      })
+    license.updatedAt = new Date(event.blockTimestamp)
+    integrateMeta(license, licenseMetadata, ['attribution', 'code', 'customText'])
+    await store.save<License>(license)
+  }
+
+  // Update license (and potentially remove foreign key reference)
+  // FIXME: Note that we MUST to provide "null" here in order to unset a relation,
+  // See: https://github.com/Joystream/hydra/issues/435
+  video.license = license as License | undefined
+  video.updatedAt = new Date(ctx.event.blockTimestamp)
+  await store.save<Video>(video)
+
+  // Safely remove previous license if needed
+  if (previousLicense && !license) {
+    await store.remove<License>(previousLicense)
+  }
+}
+
+/*
+  Checks if protobof contains license with some fields filled or is empty object (`{}` or `{someKey: undefined, ...}`).
+  Empty object means deletion is requested.
+*/
+function isLicenseEmpty(licenseObject: ILicense): boolean {
+  const somePropertySet = Object.values(licenseObject).some((v) => isSet(v))
+
+  return !somePropertySet
+}
+
+async function processVideoCategory(
+  ctx: EventContext & StoreContext,
+  currentCategory: VideoCategory | undefined,
+  categoryId: number
+): Promise<VideoCategory | undefined> {
+  const { store } = ctx
+
+  // load video category
+  const category = await store.get(VideoCategory, {
+    where: { id: categoryId.toString() },
+  })
+
+  // ensure video category exists
+  if (!category) {
+    invalidMetadata('Non-existing video category association with video requested', categoryId)
+    return currentCategory
+  }
+
+  return category
+}
+
+async function processChannelCategory(
+  ctx: EventContext & StoreContext,
+  currentCategory: ChannelCategory | undefined,
+  categoryId: number
+): Promise<ChannelCategory | undefined> {
+  const { store } = ctx
+
+  // load video category
+  const category = await store.get(ChannelCategory, {
+    where: { id: categoryId.toString() },
+  })
+
+  // ensure video category exists
+  if (!category) {
+    invalidMetadata('Non-existing channel category association with channel requested', categoryId)
+    return currentCategory
+  }
+
+  return category
+}

+ 271 - 0
query-node/mappings/content/video.ts

@@ -0,0 +1,271 @@
+/*
+eslint-disable @typescript-eslint/naming-convention
+*/
+import { EventContext, StoreContext } from '@joystream/hydra-common'
+import { In } from 'typeorm'
+import { Content } from '../generated/types'
+import { deserializeMetadata, inconsistentState, logger } from '../common'
+import { processVideoMetadata } from './utils'
+import { Channel, Video, VideoCategory, AssetNone } from 'query-node/dist/model'
+import { VideoMetadata, VideoCategoryMetadata } from '@joystream/metadata-protobuf'
+import { integrateMeta } from '@joystream/metadata-protobuf/utils'
+import _ from 'lodash'
+
+export async function content_VideoCategoryCreated({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoCategoryId, videoCategoryCreationParameters] = new Content.VideoCategoryCreatedEvent(event).params
+
+  // read metadata
+  const metadata = (await deserializeMetadata(VideoCategoryMetadata, videoCategoryCreationParameters.meta)) || {}
+
+  // create new video category
+  const videoCategory = new VideoCategory({
+    // main data
+    id: videoCategoryId.toString(),
+    videos: [],
+    createdInBlock: event.blockNumber,
+    // fill in auto-generated fields
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+  })
+  integrateMeta(videoCategory, metadata, ['name'])
+
+  // save video category
+  await store.save<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been created', { id: videoCategoryId })
+}
+
+export async function content_VideoCategoryUpdated({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoCategoryId, videoCategoryUpdateParameters] = new Content.VideoCategoryUpdatedEvent(event).params
+
+  // load video category
+  const videoCategory = await store.get(VideoCategory, {
+    where: { id: videoCategoryId.toString() },
+  })
+
+  // ensure video category exists
+  if (!videoCategory) {
+    return inconsistentState('Non-existing video category update requested', videoCategoryId)
+  }
+
+  // read metadata
+  const newMeta = deserializeMetadata(VideoCategoryMetadata, videoCategoryUpdateParameters.new_meta) || {}
+  integrateMeta(videoCategory, newMeta, ['name'])
+
+  // set last update time
+  videoCategory.updatedAt = new Date(event.blockTimestamp)
+
+  // save video category
+  await store.save<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been updated', { id: videoCategoryId })
+}
+
+export async function content_VideoCategoryDeleted({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoCategoryId] = new Content.VideoCategoryDeletedEvent(event).params
+
+  // load video category
+  const videoCategory = await store.get(VideoCategory, {
+    where: { id: videoCategoryId.toString() },
+  })
+
+  // ensure video category exists
+  if (!videoCategory) {
+    return inconsistentState('Non-existing video category deletion requested', videoCategoryId)
+  }
+
+  // remove video category
+  await store.remove<VideoCategory>(videoCategory)
+
+  // emit log event
+  logger.info('Video category has been deleted', { id: videoCategoryId })
+}
+
+/// //////////////// Video //////////////////////////////////////////////////////
+
+export async function content_VideoCreated(ctx: EventContext & StoreContext): Promise<void> {
+  const { store, event } = ctx
+  // read event data
+  const [, channelId, videoId, videoCreationParameters] = new Content.VideoCreatedEvent(event).params
+
+  // load channel
+  const channel = await store.get(Channel, { where: { id: channelId.toString() } })
+
+  // ensure channel exists
+  if (!channel) {
+    return inconsistentState('Trying to add video to non-existing channel', channelId)
+  }
+
+  const video = new Video({
+    id: videoId.toString(),
+    channel,
+    isCensored: false,
+    isFeatured: false,
+    createdInBlock: event.blockNumber,
+    thumbnailPhoto: new AssetNone(),
+    media: new AssetNone(),
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+  })
+  // deserialize & process metadata
+  const metadata = deserializeMetadata(VideoMetadata, videoCreationParameters.meta) || {}
+  await processVideoMetadata(ctx, channel, video, metadata, videoCreationParameters.assets)
+
+  // save video
+  await store.save<Video>(video)
+
+  // emit log event
+  logger.info('Video has been created', { id: videoId })
+}
+
+export async function content_VideoUpdated(ctx: EventContext & StoreContext): Promise<void> {
+  const { event, store } = ctx
+  // read event data
+  const [, videoId, videoUpdateParameters] = new Content.VideoUpdatedEvent(event).params
+
+  // load video
+  const video = await store.get(Video, {
+    where: { id: videoId.toString() },
+    relations: ['channel', 'license'],
+  })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video update requested', videoId)
+  }
+
+  // prepare changed metadata
+  const newMetadataBytes = videoUpdateParameters.new_meta.unwrapOr(null)
+
+  // update metadata if it was changed
+  if (newMetadataBytes) {
+    const newMetadata = deserializeMetadata(VideoMetadata, newMetadataBytes) || {}
+    await processVideoMetadata(ctx, video.channel, video, newMetadata, videoUpdateParameters.assets.unwrapOr([]))
+  }
+
+  // set last update time
+  video.updatedAt = new Date(event.blockTimestamp)
+
+  // save video
+  await store.save<Video>(video)
+
+  // emit log event
+  logger.info('Video has been updated', { id: videoId })
+}
+
+export async function content_VideoDeleted({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoId] = new Content.VideoDeletedEvent(event).params
+
+  // load video
+  const video = await store.get(Video, { where: { id: videoId.toString() } })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video deletion requested', videoId)
+  }
+
+  // remove video
+  await store.remove<Video>(video)
+
+  // emit log event
+  logger.info('Video has been deleted', { id: videoId })
+}
+
+export async function content_VideoCensorshipStatusUpdated({
+  store,
+  event,
+}: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoId, isCensored] = new Content.VideoCensorshipStatusUpdatedEvent(event).params
+
+  // load video
+  const video = await store.get(Video, { where: { id: videoId.toString() } })
+
+  // ensure video exists
+  if (!video) {
+    return inconsistentState('Non-existing video censoring requested', videoId)
+  }
+
+  // update video
+  video.isCensored = isCensored.isTrue
+
+  // set last update time
+  video.updatedAt = new Date(event.blockTimestamp)
+
+  // save video
+  await store.save<Video>(video)
+
+  // emit log event
+  logger.info('Video censorship status has been updated', { id: videoId, isCensored: isCensored.isTrue })
+}
+
+export async function content_FeaturedVideosSet({ store, event }: EventContext & StoreContext): Promise<void> {
+  // read event data
+  const [, videoIds] = new Content.FeaturedVideosSetEvent(event).params
+
+  // load old featured videos
+  const existingFeaturedVideos = await store.getMany(Video, { where: { isFeatured: true } })
+
+  // comparsion utility
+  const isSame = (videoIdA: string) => (videoIdB: string) => videoIdA === videoIdB
+
+  // calculate diff sets
+  const videosToRemove = existingFeaturedVideos.filter(
+    (existingFV) => !videoIds.map((videoId) => videoId.toString()).some(isSame(existingFV.id))
+  )
+  const videoIdsToAdd = videoIds.filter(
+    (videoId) => !existingFeaturedVideos.map((existingFV) => existingFV.id).some(isSame(videoId.toString()))
+  )
+
+  // mark previously featured videos as not-featured
+  await Promise.all(
+    videosToRemove.map(async (video) => {
+      video.isFeatured = false
+      // set last update time
+      video.updatedAt = new Date(event.blockTimestamp)
+
+      await store.save<Video>(video)
+    })
+  )
+
+  // read previously not-featured videos that are meant to be featured
+  const videosToAdd = await store.getMany(Video, {
+    where: {
+      id: In(videoIdsToAdd.map((item) => item.toString())),
+    },
+  })
+
+  if (videosToAdd.length !== videoIdsToAdd.length) {
+    // Do not throw, as this is not validated by the runtime
+    console.warn(
+      'Non-existing video(s) in featuredVideos set:',
+      _.difference(
+        videoIdsToAdd.map((v) => v.toString()),
+        videosToAdd.map((v) => v.id)
+      )
+    )
+  }
+
+  // mark previously not-featured videos as featured
+  await Promise.all(
+    videosToAdd.map(async (video) => {
+      video.isFeatured = true
+
+      // set last update time
+      video.updatedAt = new Date(event.blockTimestamp)
+
+      await store.save<Video>(video)
+    })
+  )
+
+  // emit log event
+  const addedVideoIds = videosToAdd.map((v) => v.id)
+  const removedVideoIds = videosToRemove.map((v) => v.id)
+  logger.info('Featured videos have been updated', { addedVideoIds, removedVideoIds })
+}

+ 8 - 0
query-node/mappings/genesis-data/index.ts

@@ -0,0 +1,8 @@
+import { MemberJson, StorageSystemJson } from './types'
+import storageSystemJson from './storageSystem.json'
+import membersJson from './members.json'
+
+const storageSystem: StorageSystemJson = storageSystemJson
+const members: MemberJson[] = membersJson
+
+export { storageSystem, members }

+ 0 - 0
query-node/mappings/sumer/bootstrap/data/members.json → query-node/mappings/genesis-data/members.json


+ 10 - 0
query-node/mappings/genesis-data/storageSystem.json

@@ -0,0 +1,10 @@
+{
+  "id": "1",
+  "blacklist": [],
+  "storageBucketsPerBagLimit": 0,
+  "distributionBucketsPerBagLimit": 0,
+  "uploadingBlocked": false,
+  "dataObjectFeePerMb": 0,
+  "storageBucketMaxObjectsCountLimit": 0,
+  "storageBucketMaxObjectsSizeLimit": 0
+}

+ 20 - 0
query-node/mappings/genesis-data/types.ts

@@ -0,0 +1,20 @@
+export type MemberJson = {
+  member_id: string
+  root_account: string
+  controller_account: string
+  handle: string
+  about?: string
+  avatar_uri?: string
+  registered_at_time: number
+}
+
+export type StorageSystemJson = {
+  id: string
+  blacklist: string[]
+  storageBucketsPerBagLimit: number
+  distributionBucketsPerBagLimit: number
+  uploadingBlocked: boolean
+  dataObjectFeePerMb: number | string
+  storageBucketMaxObjectsCountLimit: number | string
+  storageBucketMaxObjectsSizeLimit: number | string
+}

+ 35 - 0
query-node/mappings/genesis.ts

@@ -0,0 +1,35 @@
+import { StoreContext } from '@joystream/hydra-common'
+import BN from 'bn.js'
+import { Membership, MembershipEntryMethod, StorageSystemParameters } from 'query-node/dist/model'
+import { storageSystem, members } from './genesis-data'
+
+export async function loadGenesisData({ store }: StoreContext): Promise<void> {
+  // Storage system
+  await store.save<StorageSystemParameters>(
+    new StorageSystemParameters({
+      ...storageSystem,
+      storageBucketMaxObjectsCountLimit: new BN(storageSystem.storageBucketMaxObjectsCountLimit),
+      storageBucketMaxObjectsSizeLimit: new BN(storageSystem.storageBucketMaxObjectsSizeLimit),
+      dataObjectFeePerMb: new BN(storageSystem.dataObjectFeePerMb),
+    })
+  )
+  // Members
+  for (const m of members) {
+    // create new membership
+    const member = new Membership({
+      // main data
+      id: m.member_id,
+      rootAccount: m.root_account,
+      controllerAccount: m.controller_account,
+      handle: m.handle,
+      about: m.about,
+      avatarUri: m.avatar_uri,
+      createdInBlock: 0,
+      entry: MembershipEntryMethod.GENESIS,
+      // fill in auto-generated fields
+      createdAt: new Date(m.registered_at_time),
+      updatedAt: new Date(m.registered_at_time),
+    })
+    await store.save<Membership>(member)
+  }
+}

+ 0 - 63
query-node/mappings/giza/common.ts

@@ -1,63 +0,0 @@
-import { DatabaseManager } from '@joystream/hydra-common'
-import { BaseModel } from '@joystream/warthog'
-import { WorkingGroup } from '@joystream/types/augment/all'
-import { AnyMetadataClass, DecodedMetadataObject } from '@joystream/metadata-protobuf/types'
-import { metaToObject } from '@joystream/metadata-protobuf/utils'
-import { Bytes } from '@polkadot/types'
-
-type EntityClass<T extends BaseModel> = {
-  new (): T
-  name: string
-}
-
-type RelationsArr<T extends BaseModel> = Exclude<
-  keyof T & string,
-  { [K in keyof T]: T[K] extends BaseModel | undefined ? '' : T[K] extends BaseModel[] | undefined ? '' : K }[keyof T]
->[]
-
-export async function getById<T extends BaseModel>(
-  store: DatabaseManager,
-  entityClass: EntityClass<T>,
-  id: string,
-  relations?: RelationsArr<T>
-): Promise<T> {
-  const result = await store.get(entityClass, { where: { id }, relations })
-  if (!result) {
-    throw new Error(`Expected ${entityClass.name} not found by ID: ${id}`)
-  }
-
-  return result
-}
-
-export type WorkingGroupModuleName = 'storageWorkingGroup' | 'contentDirectoryWorkingGroup'
-
-export function getWorkingGroupModuleName(group: WorkingGroup): WorkingGroupModuleName {
-  if (group.isContent) {
-    return 'contentDirectoryWorkingGroup'
-  } else if (group.isStorage) {
-    return 'storageWorkingGroup'
-  }
-
-  throw new Error(`Unsupported working group encountered: ${group.type}`)
-}
-
-export function deserializeMetadata<T>(
-  metadataType: AnyMetadataClass<T>,
-  metadataBytes: Bytes
-): DecodedMetadataObject<T> | null {
-  try {
-    return metaToObject(metadataType, metadataType.decode(metadataBytes.toU8a(true)))
-  } catch (e) {
-    console.error(`Cannot deserialize ${metadataType.name}! Provided bytes: (${metadataBytes.toHex()})`)
-    return null
-  }
-}
-
-export function bytesToString(b: Bytes): string {
-  return (
-    Buffer.from(b.toU8a(true))
-      .toString()
-      // eslint-disable-next-line no-control-regex
-      .replace(/\u0000/g, '')
-  )
-}

+ 0 - 3
query-node/mappings/giza/genesis-data/index.ts

@@ -1,3 +0,0 @@
-import storageSystem from './storageSystem.json'
-
-export { storageSystem }

+ 0 - 1
query-node/mappings/giza/genesis-data/storageSystem.json

@@ -1 +0,0 @@
-{ "blacklist": [] }

+ 0 - 12
query-node/mappings/giza/genesis.ts

@@ -1,12 +0,0 @@
-import { StoreContext } from '@joystream/hydra-common'
-import { StorageSystemParameters } from 'query-node/dist/model'
-import { storageSystem } from './genesis-data'
-
-export async function loadGenesisData({ store }: StoreContext): Promise<void> {
-  // Storage system
-  await store.save<StorageSystemParameters>(
-    new StorageSystemParameters({
-      ...storageSystem,
-    })
-  )
-}

+ 0 - 2
query-node/mappings/giza/index.ts

@@ -1,2 +0,0 @@
-export * from './genesis'
-export * from './storage'

+ 3 - 2
query-node/mappings/sumer/index.ts → query-node/mappings/index.ts

@@ -1,4 +1,5 @@
-export * from './content'
 export * from './membership'
-export * from './storage'
 export * from './workingGroup'
+export * from './content'
+export * from './storage'
+export * from './genesis'

+ 37 - 45
query-node/mappings/sumer/membership.ts → query-node/mappings/membership.ts

@@ -1,25 +1,16 @@
-import { fixBlockTimestamp } from './eventFix'
 import { Bytes } from '@polkadot/types'
 import { MemberId } from '@joystream/types/members'
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { FindConditions } from 'typeorm'
-
-import {
-  convertBytesToString,
-  inconsistentState,
-  logger,
-  extractExtrinsicArgs,
-  extractSudoCallParameters,
-} from './common'
-import { Members } from '../../generated/types'
-import { MembershipEntryMethod, Membership } from 'query-node'
+import { SubstrateEvent, EventContext, StoreContext } from '@joystream/hydra-common'
+
+import { bytesToString, inconsistentState, logger, extractExtrinsicArgs, extractSudoCallParameters } from './common'
+import { Members } from './generated/types'
+import { MembershipEntryMethod, Membership } from 'query-node/dist/model'
 import { EntryMethod } from '@joystream/types/augment'
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberRegistered(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberRegistered({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
-  const { accountId, memberId, entryMethod } = new Members.MemberRegisteredEvent(event).data
+  const [memberId, accountId, entryMethod] = new Members.MemberRegisteredEvent(event).params
   const { avatarUri, about, handle } = extractExtrinsicArgs(event, Members.BuyMembershipCall, {
     handle: 1,
     avatarUri: 2,
@@ -32,26 +23,27 @@ export async function members_MemberRegistered(db: DatabaseManager, event: Subst
     id: memberId.toString(),
     rootAccount: accountId.toString(),
     controllerAccount: accountId.toString(),
-    handle: convertBytesToString(handle.unwrapOr(null)),
-    about: convertBytesToString(about.unwrapOr(null)),
-    avatarUri: convertBytesToString(avatarUri.unwrapOr(null)),
+    // Handle is required by the runtime during registration. Lack of it will throw an error
+    handle: bytesToString(handle.unwrap()),
+    about: about.isSome ? bytesToString(about.unwrap()) : undefined,
+    avatarUri: avatarUri.isSome ? bytesToString(avatarUri.unwrap()) : undefined,
     createdInBlock: event.blockNumber,
     entry: convertEntryMethod(entryMethod),
 
     // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
   })
 
   // save membership
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info('Member has been registered', { ids: memberId })
 }
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedAboutText(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberUpdatedAboutText({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
   const { text, memberId } = isUpdateMembershipExtrinsic(event)
     ? unpackUpdateMembershipOptions(
@@ -60,7 +52,7 @@ export async function members_MemberUpdatedAboutText(db: DatabaseManager, event:
     : extractExtrinsicArgs(event, Members.ChangeMemberAboutTextCall, { memberId: 0, text: 1 })
 
   // load member
-  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+  const member = await store.get(Membership, { where: { id: memberId.toString() } })
 
   // ensure member exists
   if (!member) {
@@ -68,20 +60,20 @@ export async function members_MemberUpdatedAboutText(db: DatabaseManager, event:
   }
 
   // update member
-  member.about = convertBytesToString(text)
+  member.about = bytesToString(text)
 
   // set last update time
-  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  member.updatedAt = new Date(event.blockTimestamp)
 
   // save member
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info("Member's about text has been updated", { ids: memberId })
 }
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberUpdatedAvatar({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
   const { uri, memberId } = isUpdateMembershipExtrinsic(event)
     ? unpackUpdateMembershipOptions(
@@ -90,7 +82,7 @@ export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: Su
     : extractExtrinsicArgs(event, Members.ChangeMemberAvatarCall, { memberId: 0, uri: 1 })
 
   // load member
-  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+  const member = await store.get(Membership, { where: { id: memberId.toString() } })
 
   // ensure member exists
   if (!member) {
@@ -98,20 +90,20 @@ export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: Su
   }
 
   // update member
-  member.avatarUri = convertBytesToString(uri)
+  member.avatarUri = bytesToString(uri)
 
   // set last update time
-  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  member.updatedAt = new Date(event.blockTimestamp)
 
   // save member
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info("Member's avatar has been updated", { ids: memberId })
 }
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberUpdatedHandle(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberUpdatedHandle({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
   const { handle, memberId } = isUpdateMembershipExtrinsic(event)
     ? unpackUpdateMembershipOptions(
@@ -120,7 +112,7 @@ export async function members_MemberUpdatedHandle(db: DatabaseManager, event: Su
     : extractExtrinsicArgs(event, Members.ChangeMemberHandleCall, { memberId: 0, handle: 1 })
 
   // load member
-  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+  const member = await store.get(Membership, { where: { id: memberId.toString() } })
 
   // ensure member exists
   if (!member) {
@@ -128,20 +120,20 @@ export async function members_MemberUpdatedHandle(db: DatabaseManager, event: Su
   }
 
   // update member
-  member.handle = convertBytesToString(handle)
+  member.handle = bytesToString(handle)
 
   // set last update time
-  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  member.updatedAt = new Date(event.blockTimestamp)
 
   // save member
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info("Member's avatar has been updated", { ids: memberId })
 }
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberSetRootAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberSetRootAccount({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
   const { newRootAccount, memberId } = extractExtrinsicArgs(event, Members.SetRootAccountCall, {
     memberId: 0,
@@ -149,7 +141,7 @@ export async function members_MemberSetRootAccount(db: DatabaseManager, event: S
   })
 
   // load member
-  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+  const member = await store.get(Membership, { where: { id: memberId.toString() } })
 
   // ensure member exists
   if (!member) {
@@ -160,17 +152,17 @@ export async function members_MemberSetRootAccount(db: DatabaseManager, event: S
   member.rootAccount = newRootAccount.toString()
 
   // set last update time
-  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  member.updatedAt = new Date(event.blockTimestamp)
 
   // save member
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info("Member's root has been updated", { ids: memberId })
 }
 
 // eslint-disable-next-line @typescript-eslint/naming-convention
-export async function members_MemberSetControllerAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
+export async function members_MemberSetControllerAccount({ event, store }: EventContext & StoreContext): Promise<void> {
   // read event data
   const { newControllerAccount, memberId } = extractExtrinsicArgs(event, Members.SetControllerAccountCall, {
     memberId: 0,
@@ -178,7 +170,7 @@ export async function members_MemberSetControllerAccount(db: DatabaseManager, ev
   })
 
   // load member
-  const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
+  const member = await store.get(Membership, { where: { id: memberId.toString() } })
 
   // ensure member exists
   if (!member) {
@@ -189,10 +181,10 @@ export async function members_MemberSetControllerAccount(db: DatabaseManager, ev
   member.controllerAccount = newControllerAccount.toString()
 
   // set last update time
-  member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
+  member.updatedAt = new Date(event.blockTimestamp)
 
   // save member
-  await db.save<Membership>(member)
+  await store.save<Membership>(member)
 
   // emit log event
   logger.info("Member's controller has been updated", { ids: memberId })

+ 2 - 2
query-node/mappings/package.json

@@ -9,14 +9,14 @@
     "copy-types": "cp ../../types/augment/all/defs.json lib/generated/types/typedefs.json",
     "clean": "rm -rf lib",
     "lint": "eslint . --quiet --ext .ts",
-    "checks": "tsc --noEmit --pretty && prettier ./ --check && yarn lint",
+    "checks": "prettier ./ --check && yarn lint",
     "format": "prettier ./ --write "
   },
   "dependencies": {
     "@polkadot/types": "4.2.1",
     "@joystream/hydra-common": "3.1.0-alpha.1",
     "@joystream/hydra-db-utils": "3.1.0-alpha.1",
-    "@joystream/content-metadata-protobuf": "^1.1.0",
+    "@joystream/metadata-protobuf": "^1.0.0",
     "@joystream/types": "^0.17.0",
     "@joystream/warthog": "2.35.0"
   },

+ 101 - 72
query-node/mappings/giza/storage/index.ts → query-node/mappings/storage/index.ts

@@ -2,7 +2,7 @@
 eslint-disable @typescript-eslint/naming-convention
 */
 import { DatabaseManager, EventContext, StoreContext } from '@joystream/hydra-common'
-import { Storage } from '../../generated/types/storage'
+import { Storage } from '../generated/types/storage'
 import {
   DistributionBucket,
   DistributionBucketFamily,
@@ -27,7 +27,7 @@ import {
   StorageBagStorageAssignment,
 } from 'query-node/dist/model'
 import BN from 'bn.js'
-import { getById, getWorkingGroupModuleName, bytesToString } from '../common'
+import { getById, bytesToString } from '../common'
 import { BTreeSet } from '@polkadot/types'
 import { DataObjectCreationParameters } from '@joystream/types/storage'
 import { registry } from '@joystream/types'
@@ -67,7 +67,7 @@ function getStaticBagOwner(bagId: StaticBagId): typeof StorageBagOwner {
     return new StorageBagOwnerCouncil()
   } else if (bagId.isWorkingGroup) {
     const owner = new StorageBagOwnerWorkingGroup()
-    owner.workingGroupId = getWorkingGroupModuleName(bagId.asWorkingGroup)
+    owner.workingGroupId = bagId.asWorkingGroup.toString().toLowerCase()
     return owner
   } else {
     throw new Error(`Unexpected static bag type: ${bagId.type}`)
@@ -90,9 +90,9 @@ function getDynamicBagOwner(bagId: DynamicBagId) {
 
 function getStaticBagId(bagId: StaticBagId): string {
   if (bagId.isCouncil) {
-    return `CO`
+    return `static:council`
   } else if (bagId.isWorkingGroup) {
-    return `WG-${bagId.asWorkingGroup.type}`
+    return `static:wg:${bagId.asWorkingGroup.type.toLowerCase()}`
   } else {
     throw new Error(`Unexpected static bag type: ${bagId.type}`)
   }
@@ -100,9 +100,9 @@ function getStaticBagId(bagId: StaticBagId): string {
 
 function getDynamicBagId(bagId: DynamicBagId): string {
   if (bagId.isChannel) {
-    return `CH-${bagId.asChannel.toString()}`
+    return `dynamic:channel:${bagId.asChannel.toString()}`
   } else if (bagId.isMember) {
-    return `M-${bagId.asMember.toString()}`
+    return `dynamic:member:${bagId.asMember.toString()}`
   } else {
     throw new Error(`Unexpected dynamic bag type: ${bagId.type}`)
   }
@@ -180,7 +180,16 @@ async function getDistributionBucketFamilyWithMetadata(
   return family
 }
 
-// BUCKETS
+async function getStorageSystem(store: DatabaseManager) {
+  const storageSystem = await store.get(StorageSystemParameters, {})
+  if (!storageSystem) {
+    throw new Error('Storage system entity is missing!')
+  }
+
+  return storageSystem
+}
+
+// STORAGE BUCKETS
 
 export async function storage_StorageBucketCreated({ event, store }: EventContext & StoreContext): Promise<void> {
   const [
@@ -196,6 +205,8 @@ export async function storage_StorageBucketCreated({ event, store }: EventContex
     acceptingNewBags: acceptingNewBags.isTrue,
     dataObjectCountLimit: new BN(dataObjectCountLimit.toString()),
     dataObjectsSizeLimit: new BN(dataObjectSizeLimit.toString()),
+    dataObjectsCount: new BN(0),
+    dataObjectsSize: new BN(0),
   })
   if (invitedWorkerId.isSome) {
     const operatorStatus = new StorageBucketOperatorStatusInvited()
@@ -297,10 +308,33 @@ export async function storage_StorageBucketsUpdatedForBag({
   await Promise.all(assignmentsToAdd.map((a) => store.save<StorageBagStorageAssignment>(a)))
 }
 
+export async function storage_VoucherChanged({ event, store }: EventContext & StoreContext): Promise<void> {
+  const [bucketId, voucher] = new Storage.VoucherChangedEvent(event).params
+  const bucket = await getById(store, StorageBucket, bucketId.toString())
+
+  bucket.dataObjectCountLimit = voucher.objectsLimit
+  bucket.dataObjectsSizeLimit = voucher.sizeLimit
+  bucket.dataObjectsCount = voucher.objectsUsed
+  bucket.dataObjectsSize = voucher.sizeUsed
+
+  await store.save<StorageBucket>(bucket)
+}
+
+export async function storage_StorageBucketVoucherLimitsSet({
+  event,
+  store,
+}: EventContext & StoreContext): Promise<void> {
+  const [bucketId, sizeLimit, countLimit] = new Storage.StorageBucketVoucherLimitsSetEvent(event).params
+  const bucket = await getById(store, StorageBucket, bucketId.toString())
+  bucket.dataObjectsSizeLimit = sizeLimit
+  bucket.dataObjectCountLimit = countLimit
+
+  await store.save<StorageBucket>(bucket)
+}
+
 export async function storage_StorageBucketDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
   const [bucketId] = new Storage.StorageBucketDeletedEvent(event).params
-  // TODO: Delete or just change status?
-  // TODO: Cascade remove on db level?
+  // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
   const assignments = await store.getMany(StorageBagStorageAssignment, {
     where: { storageBucket: { id: bucketId.toString() } },
   })
@@ -320,10 +354,8 @@ export async function storage_DynamicBagCreated({ event, store }: EventContext &
 
 export async function storage_DynamicBagDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
   const [, bagId] = new Storage.DynamicBagDeletedEvent(event).params
-  // TODO: Delete or just change status?
-  // TODO: Cascade remove on db level?
   const storageBag = await getDynamicBag(store, bagId, ['objects'])
-  await Promise.all((storageBag.objects || []).map((o) => store.remove<StorageDataObject>(o)))
+  // The bag should already be empty, so no cascade-remove required
   await store.remove<StorageBag>(storageBag)
 }
 
@@ -332,13 +364,12 @@ export async function storage_DynamicBagDeleted({ event, store }: EventContext &
 // Note: "Uploaded" here actually means "created" (the real upload happens later)
 export async function storage_DataObjectsUploaded({ event, store }: EventContext & StoreContext): Promise<void> {
   const [dataObjectIds, uploadParams] = new Storage.DataObjectsUploadedEvent(event).params
-  const { bagId, authenticationKey, objectCreationList } = uploadParams
+  const { bagId, objectCreationList } = uploadParams
   const storageBag = await getBag(store, bagId)
   const dataObjects = dataObjectIds.map((objectId, i) => {
     const objectParams = new DataObjectCreationParameters(registry, objectCreationList[i].toJSON() as any)
     return new StorageDataObject({
       id: objectId.toString(),
-      authenticationKey: bytesToString(authenticationKey),
       isAccepted: false,
       ipfsHash: bytesToString(objectParams.ipfsContentId),
       size: new BN(objectParams.getField('size').toString()),
@@ -354,8 +385,6 @@ export async function storage_PendingDataObjectsAccepted({ event, store }: Event
   await Promise.all(
     dataObjects.map(async (dataObject) => {
       dataObject.isAccepted = true
-      // TODO: Do we still want other storage providers to accept it? How long should the key be valid?
-      // dataObject.authenticationKey = null as any
       await store.save<StorageDataObject>(dataObject)
     })
   )
@@ -376,24 +405,10 @@ export async function storage_DataObjectsMoved({ event, store }: EventContext &
 export async function storage_DataObjectsDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
   const [, bagId, dataObjectIds] = new Storage.DataObjectsDeletedEvent(event).params
   const dataObjects = await getDataObjectsInBag(store, bagId, dataObjectIds)
-  // TODO: Delete them or just change status?
-  // (may not be so optimal if we expect a large amount of data objects)
   await Promise.all(dataObjects.map((o) => store.remove<StorageDataObject>(o)))
 }
 
-// BLACKLIST
-export async function storage_UpdateBlacklist({ event, store }: EventContext & StoreContext): Promise<void> {
-  const [removedContentIds, addedContentIds] = new Storage.UpdateBlacklistEvent(event).params
-  const storageSystem = await store.get(StorageSystemParameters, {})
-  if (!storageSystem) {
-    throw new Error('StorageSystemParameters entity not found!')
-  }
-  storageSystem.blacklist = storageSystem.blacklist
-    .filter((cid) => !Array.from(removedContentIds).some((id) => id.eq(cid)))
-    .concat(Array.from(addedContentIds).map((id) => id.toString()))
-
-  await store.save<StorageSystemParameters>(storageSystem)
-}
+// DISTRIBUTION FAMILY
 
 export async function storage_DistributionBucketFamilyCreated({
   event,
@@ -408,6 +423,18 @@ export async function storage_DistributionBucketFamilyCreated({
   await store.save<DistributionBucketFamily>(family)
 }
 
+export async function storage_DistributionBucketFamilyMetadataSet({
+  event,
+  store,
+}: EventContext & StoreContext): Promise<void> {
+  const [familyId, metadataBytes] = new Storage.DistributionBucketFamilyMetadataSetEvent(event).params
+
+  const family = await getDistributionBucketFamilyWithMetadata(store, familyId.toString())
+  family.metadata = await processDistributionBucketFamilyMetadata(store, family.metadata, metadataBytes)
+
+  await store.save<DistributionBucketFamily>(family)
+}
+
 export async function storage_DistributionBucketFamilyDeleted({
   event,
   store,
@@ -419,6 +446,8 @@ export async function storage_DistributionBucketFamilyDeleted({
   await store.remove(family)
 }
 
+// DISTRIBUTION BUCKET
+
 export async function storage_DistributionBucketCreated({ event, store }: EventContext & StoreContext): Promise<void> {
   const [familyId, acceptingNewBags, bucketId] = new Storage.DistributionBucketCreatedEvent(event).params
 
@@ -447,8 +476,7 @@ export async function storage_DistributionBucketStatusUpdated({
 
 export async function storage_DistributionBucketDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
   const [, bucketId] = new Storage.DistributionBucketDeletedEvent(event).params
-  // TODO: Delete or just change status?
-  // TODO: Cascade remove on db level?
+  // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
   const assignments = await store.getMany(StorageBagDistributionAssignment, {
     where: { distributionBucket: { id: bucketId.toString() } },
   })
@@ -551,7 +579,7 @@ export async function storage_DistributionBucketOperatorRemoved({
 }: EventContext & StoreContext): Promise<void> {
   const [, bucketId, workerId] = new Storage.DistributionBucketOperatorRemovedEvent(event).params
 
-  // TODO: Cascade remove
+  // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
 
   const operator = await getDistributionBucketOperatorWithMetadata(store, `${bucketId}-${workerId}`)
   await store.remove<DistributionBucketOperator>(operator)
@@ -566,74 +594,75 @@ export async function storage_DistributionBucketOperatorRemoved({
   }
 }
 
-export async function storage_DistributionBucketFamilyMetadataSet({
-  event,
-  store,
-}: EventContext & StoreContext): Promise<void> {
-  const [familyId, metadataBytes] = new Storage.DistributionBucketFamilyMetadataSetEvent(event).params
+// STORAGE SYSTEM GLOBAL PARAMS
 
-  const family = await getDistributionBucketFamilyWithMetadata(store, familyId.toString())
-  family.metadata = await processDistributionBucketFamilyMetadata(store, family.metadata, metadataBytes)
+export async function storage_UpdateBlacklist({ event, store }: EventContext & StoreContext): Promise<void> {
+  const [removedContentIds, addedContentIds] = new Storage.UpdateBlacklistEvent(event).params
+  const storageSystem = await getStorageSystem(store)
+  storageSystem.blacklist = storageSystem.blacklist
+    .filter((cid) => !Array.from(removedContentIds).some((id) => id.eq(cid)))
+    .concat(Array.from(addedContentIds).map((id) => id.toString()))
 
-  await store.save<DistributionBucketFamily>(family)
+  await store.save<StorageSystemParameters>(storageSystem)
 }
 
 export async function storage_DistributionBucketsPerBagLimitUpdated({
   event,
   store,
 }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
+  const [newLimit] = new Storage.DistributionBucketsPerBagLimitUpdatedEvent(event).params
+  const storageSystem = await getStorageSystem(store)
+
+  storageSystem.distributionBucketsPerBagLimit = newLimit.toNumber()
+
+  await store.save<StorageSystemParameters>(storageSystem)
 }
 
-export async function storage_FamiliesInDynamicBagCreationPolicyUpdated({
+export async function storage_StorageBucketsPerBagLimitUpdated({
   event,
   store,
 }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
+  const [newLimit] = new Storage.StorageBucketsPerBagLimitUpdatedEvent(event).params
+  const storageSystem = await getStorageSystem(store)
+
+  storageSystem.storageBucketsPerBagLimit = newLimit.toNumber()
+
+  await store.save<StorageSystemParameters>(storageSystem)
 }
 
-export async function storage_StorageBucketVoucherLimitsSet({
+export async function storage_StorageBucketsVoucherMaxLimitsUpdated({
   event,
   store,
 }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
+  const [sizeLimit, countLimit] = new Storage.StorageBucketsVoucherMaxLimitsUpdatedEvent(event).params
+  const storageSystem = await getStorageSystem(store)
+
+  storageSystem.storageBucketMaxObjectsSizeLimit = sizeLimit
+  storageSystem.storageBucketMaxObjectsCountLimit = countLimit
+
+  await store.save<StorageSystemParameters>(storageSystem)
 }
 
 export async function storage_UploadingBlockStatusUpdated({
   event,
   store,
 }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
-}
+  const [isBlocked] = new Storage.UploadingBlockStatusUpdatedEvent(event).params
+  const storageSystem = await getStorageSystem(store)
 
-export async function storage_DataObjectPerMegabyteFeeUpdated({
-  event,
-  store,
-}: EventContext & StoreContext): Promise<void> {
-  // To be implemented
-}
+  storageSystem.uploadingBlocked = isBlocked.isTrue
 
-export async function storage_StorageBucketsPerBagLimitUpdated({
-  event,
-  store,
-}: EventContext & StoreContext): Promise<void> {
-  // To be implemented
+  await store.save<StorageSystemParameters>(storageSystem)
 }
 
-export async function storage_StorageBucketsVoucherMaxLimitsUpdated({
+export async function storage_DataObjectPerMegabyteFeeUpdated({
   event,
   store,
 }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
-}
+  const [newFee] = new Storage.DataObjectPerMegabyteFeeUpdatedEvent(event).params
+  const storageSystem = await getStorageSystem(store)
 
-export async function storage_VoucherChanged({ event, store }: EventContext & StoreContext): Promise<void> {
-  // To be implemented
-}
+  storageSystem.dataObjectFeePerMb = newFee
 
-export async function storage_NumberOfStorageBucketsInDynamicBagCreationPolicyUpdated({
-  event,
-  store,
-}: EventContext & StoreContext): Promise<void> {
-  // To be implemented
+  await store.save<StorageSystemParameters>(storageSystem)
 }

+ 0 - 0
query-node/mappings/giza/storage/metadata.ts → query-node/mappings/storage/metadata.ts


+ 0 - 1
query-node/mappings/sumer/bootstrap/data/workers.json

@@ -1 +0,0 @@
-{}

+ 0 - 69
query-node/mappings/sumer/bootstrap/index.ts

@@ -1,69 +0,0 @@
-import { createDBConnection } from '@dzlzv/hydra-processor/lib/db'
-import { DatabaseManager, makeDatabaseManager } from '@dzlzv/hydra-db-utils'
-import { Connection, getManager, FindConditions } from 'typeorm'
-
-import { bootMembers, IBootstrapMember } from './members'
-import { bootWorkers, IBootstrapWorker, IBootstrapWorkers } from './workers'
-import { Worker, WorkerType } from 'query-node'
-
-import fs from 'fs'
-import path from 'path'
-
-// run bootstrap
-init()
-
-// bootstrap flow
-async function init() {
-  // prepare database and import data
-  const [databaseManager, connection] = await createDatabaseManager()
-
-  // escape if db is already initialized
-  if (await isDbInitialized(databaseManager)) {
-    await connection.close()
-    return
-  }
-
-  // load import data
-  const data = loadData()
-
-  // bootstrap entities
-  await bootMembers(databaseManager, data.members)
-  await bootWorkers(databaseManager, data.workers)
-
-  await connection.close()
-}
-
-async function isDbInitialized(db: DatabaseManager): Promise<boolean> {
-  // simple way to check if db is bootstrapped already - check if there is at least 1 storage provider
-  const membership = await db.get(Worker, {
-    where: {
-      type: WorkerType.STORAGE,
-    } as FindConditions<Worker>,
-  })
-
-  return !!membership
-}
-
-async function createDatabaseManager(): Promise<[DatabaseManager, Connection]> {
-  // paths in `entities` should be the same as `entities` set in `manifest.yml`
-  const entities = ['generated/graphql-server/dist/**/*.model.js']
-
-  // connect to db and create manager
-  const connection = await createDBConnection(entities)
-  const entityManager = getManager(connection.name)
-  const databaseManager = makeDatabaseManager(entityManager)
-
-  return [databaseManager, connection]
-}
-
-interface IBootstrapData {
-  members: IBootstrapMember[]
-  workers: IBootstrapWorkers
-}
-
-function loadData(): IBootstrapData {
-  return {
-    members: JSON.parse(fs.readFileSync(process.env.BOOTSTRAP_DATA_FOLDER + '/members.json').toString()),
-    workers: JSON.parse(fs.readFileSync(process.env.BOOTSTRAP_DATA_FOLDER + '/workers.json').toString()),
-  }
-}

+ 0 - 42
query-node/mappings/sumer/bootstrap/members.ts

@@ -1,42 +0,0 @@
-// import { Connection } from 'typeorm'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { logger } from '../src/common'
-import { MembershipEntryMethod, Membership } from 'query-node'
-
-export interface IBootstrapMember {
-  member_id: number
-  root_account: string
-  controller_account: string
-  handle: string
-  avatar_uri: string
-  about: string
-  registered_at_time: number
-}
-
-// export async function bootMembers(members: IBootstrapMember[], db: Connection): Promise<void> {
-export async function bootMembers(db: DatabaseManager, members: IBootstrapMember[]): Promise<void> {
-  for (const rawMember of members) {
-    // create new membership
-    const member = new Membership({
-      // main data
-      id: rawMember.member_id.toString(),
-      rootAccount: rawMember.root_account,
-      controllerAccount: rawMember.controller_account,
-      handle: rawMember.handle,
-      about: rawMember.about,
-      avatarUri: rawMember.avatar_uri,
-      createdInBlock: 0,
-      entry: MembershipEntryMethod.GENESIS,
-
-      // fill in auto-generated fields
-      createdAt: new Date(rawMember.registered_at_time),
-      updatedAt: new Date(rawMember.registered_at_time),
-    })
-
-    // save membership
-    await db.save<Membership>(member)
-
-    // emit log event
-    logger.info('Member has been bootstrapped', { id: rawMember.member_id })
-  }
-}

+ 0 - 48
query-node/mappings/sumer/bootstrap/workers.ts

@@ -1,48 +0,0 @@
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { Worker, WorkerType } from 'query-node'
-import { logger, getNextId } from '../src/common'
-
-export interface IBootstrapWorkers {
-  storage: IBootstrapWorker[]
-  gateway: IBootstrapWorker[]
-}
-
-export interface IBootstrapWorker {
-  id: string
-  created_at: string
-}
-
-export async function bootWorkers(db: DatabaseManager, workers: IBootstrapWorkers): Promise<void> {
-  await bootWorkersInGroup(db, workers.storage, WorkerType.STORAGE)
-  await bootWorkersInGroup(db, workers.gateway, WorkerType.GATEWAY)
-}
-
-export async function bootWorkersInGroup(
-  db: DatabaseManager,
-  workers: IBootstrapWorker[],
-  workerType: WorkerType
-): Promise<void> {
-  if (!workers) {
-    return
-  }
-
-  for (const rawWorker of workers) {
-    // create new membership
-    const worker = new Worker({
-      // main data
-      id: await getNextId(db),
-      workerId: rawWorker.id,
-      type: workerType,
-      isActive: true,
-
-      createdAt: new Date(rawWorker.created_at),
-      updatedAt: new Date(rawWorker.created_at),
-    })
-
-    // save worker
-    await db.save<Worker>(worker)
-
-    // emit log event
-    logger.info('Worker has been bootstrapped', { id: rawWorker.id, workerType })
-  }
-}

+ 0 - 279
query-node/mappings/sumer/content/channel.ts

@@ -1,279 +0,0 @@
-import { fixBlockTimestamp } from '../eventFix'
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import ISO6391 from 'iso-639-1'
-import { FindConditions, In } from 'typeorm'
-
-import { AccountId } from '@polkadot/types/interfaces'
-import { Option } from '@polkadot/types/codec'
-import { Content } from '../../../generated/types'
-import {
-  readProtobuf,
-  readProtobufWithAssets,
-  convertContentActorToChannelOwner,
-  convertContentActorToDataObjectOwner,
-} from './utils'
-
-import { Channel, ChannelCategory, DataObject, AssetAvailability } from 'query-node'
-import { inconsistentState, logger } from '../common'
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelCreated(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { channelId, channelCreationParameters, contentActor } = new Content.ChannelCreatedEvent(event).data
-
-  // read metadata
-  const protobufContent = await readProtobufWithAssets(new Channel(), {
-    metadata: channelCreationParameters.meta,
-    db,
-    event,
-    assets: channelCreationParameters.assets,
-    contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
-  })
-
-  // create entity
-  const channel = new Channel({
-    // main data
-    id: channelId.toString(),
-    isCensored: false,
-    videos: [],
-    createdInBlock: event.blockNumber,
-
-    // default values for properties that might or might not be filled by metadata
-    coverPhotoUrls: [],
-    coverPhotoAvailability: AssetAvailability.INVALID,
-    avatarPhotoUrls: [],
-    avatarPhotoAvailability: AssetAvailability.INVALID,
-
-    // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    // prepare channel owner (handles fields `ownerMember` and `ownerCuratorGroup`)
-    ...(await convertContentActorToChannelOwner(db, contentActor)),
-
-    // integrate metadata
-    ...protobufContent,
-  })
-
-  // save entity
-  await db.save<Channel>(channel)
-
-  // emit log event
-  logger.info('Channel has been created', { id: channel.id })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelId, channelUpdateParameters, contentActor } = new Content.ChannelUpdatedEvent(event).data
-
-  // load channel
-  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
-
-  // ensure channel exists
-  if (!channel) {
-    return inconsistentState('Non-existing channel update requested', channelId)
-  }
-
-  // prepare changed metadata
-  const newMetadata = channelUpdateParameters.new_meta.unwrapOr(null)
-
-  //  update metadata if it was changed
-  if (newMetadata) {
-    const protobufContent = await readProtobufWithAssets(new Channel(), {
-      metadata: newMetadata,
-      db,
-      event,
-      assets: channelUpdateParameters.assets.unwrapOr([]),
-      contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
-    })
-
-    // update all fields read from protobuf
-    for (const [key, value] of Object.entries(protobufContent)) {
-      channel[key] = value
-    }
-  }
-
-  // prepare changed reward account
-  const newRewardAccount = channelUpdateParameters.reward_account.unwrapOr(null)
-
-  // reward account change happened?
-  if (newRewardAccount) {
-    // this will change the `channel`!
-    handleChannelRewardAccountChange(channel, newRewardAccount)
-  }
-
-  // set last update time
-  channel.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save channel
-  await db.save<Channel>(channel)
-
-  // emit log event
-  logger.info('Channel has been updated', { id: channel.id })
-}
-
-export async function content_ChannelAssetsRemoved(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { contentId: contentIds } = new Content.ChannelAssetsRemovedEvent(event).data
-
-  // load channel
-  const assets = await db.getMany(DataObject, {
-    where: {
-      id: In(contentIds.toArray().map((item) => item.toString())),
-    } as FindConditions<DataObject>,
-  })
-
-  // delete assets
-  for (const asset of assets) {
-    await db.remove<DataObject>(asset)
-  }
-
-  // emit log event
-  logger.info('Channel assets have been removed', { ids: contentIds })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelCensorshipStatusUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelId, isCensored } = new Content.ChannelCensorshipStatusUpdatedEvent(event).data
-
-  // load event
-  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
-
-  // ensure channel exists
-  if (!channel) {
-    return inconsistentState('Non-existing channel censoring requested', channelId)
-  }
-
-  // update channel
-  channel.isCensored = isCensored.isTrue
-
-  // set last update time
-  channel.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save channel
-  await db.save<Channel>(channel)
-
-  // emit log event
-  logger.info('Channel censorship status has been updated', { id: channelId, isCensored: isCensored.isTrue })
-}
-
-/// ///////////////// ChannelCategory ////////////////////////////////////////////
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelCategoryCreated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelCategoryCreationParameters, channelCategoryId } = new Content.ChannelCategoryCreatedEvent(event).data
-
-  // read metadata
-  const protobufContent = await readProtobuf(new ChannelCategory(), {
-    metadata: channelCategoryCreationParameters.meta,
-    db,
-    event,
-  })
-
-  // create new channel category
-  const channelCategory = new ChannelCategory({
-    // main data
-    id: channelCategoryId.toString(),
-    channels: [],
-    createdInBlock: event.blockNumber,
-
-    // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    // integrate metadata
-    ...protobufContent,
-  })
-
-  // save channel
-  await db.save<ChannelCategory>(channelCategory)
-
-  // emit log event
-  logger.info('Channel category has been created', { id: channelCategory.id })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelCategoryUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelCategoryId, channelCategoryUpdateParameters } = new Content.ChannelCategoryUpdatedEvent(event).data
-
-  // load channel category
-  const channelCategory = await db.get(ChannelCategory, {
-    where: {
-      id: channelCategoryId.toString(),
-    } as FindConditions<ChannelCategory>,
-  })
-
-  // ensure channel exists
-  if (!channelCategory) {
-    return inconsistentState('Non-existing channel category update requested', channelCategoryId)
-  }
-
-  // read metadata
-  const protobufContent = await readProtobuf(new ChannelCategory(), {
-    metadata: channelCategoryUpdateParameters.new_meta,
-    db,
-    event,
-  })
-
-  // update all fields read from protobuf
-  for (const [key, value] of Object.entries(protobufContent)) {
-    channelCategory[key] = value
-  }
-
-  // set last update time
-  channelCategory.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save channel category
-  await db.save<ChannelCategory>(channelCategory)
-
-  // emit log event
-  logger.info('Channel category has been updated', { id: channelCategory.id })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_ChannelCategoryDeleted(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelCategoryId } = new Content.ChannelCategoryDeletedEvent(event).data
-
-  // load channel category
-  const channelCategory = await db.get(ChannelCategory, {
-    where: {
-      id: channelCategoryId.toString(),
-    } as FindConditions<ChannelCategory>,
-  })
-
-  // ensure channel category exists
-  if (!channelCategory) {
-    return inconsistentState('Non-existing channel category deletion requested', channelCategoryId)
-  }
-
-  // delete channel category
-  await db.remove<ChannelCategory>(channelCategory)
-
-  // emit log event
-  logger.info('Channel category has been deleted', { id: channelCategory.id })
-}
-
-/// ///////////////// Helpers ////////////////////////////////////////////////////
-
-function handleChannelRewardAccountChange(
-  channel: Channel, // will be modified inside of the function!
-  reward_account: Option<AccountId>
-) {
-  const rewardAccount = reward_account.unwrapOr(null)
-
-  // new different reward account set?
-  if (rewardAccount) {
-    channel.rewardAccount = rewardAccount.toString()
-    return
-  }
-
-  // reward account removed
-
-  channel.rewardAccount = undefined // plan deletion (will have effect when saved to db)
-}

+ 0 - 773
query-node/mappings/sumer/content/utils.ts

@@ -1,773 +0,0 @@
-// TODO: finish db cascade on save/remove; right now there is manually added `cascade: ["insert", "update"]` directive
-//       to all relations in `query-node/generated/graphql-server/src/modules/**/*.model.ts`. That should ensure all records
-//       are saved on one `db.save(...)` call. Missing features
-//       - find a proper way to cascade on remove or implement custom removals for every entity
-//       - convert manual changes done to `*model.ts` file into some patch or bash commands that can be executed
-//         every time query node codegen is run (that will overwrite said manual changes)
-//       - verify in integration tests that the records are trully created/updated/removed as expected
-
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { Bytes } from '@polkadot/types'
-import ISO6391 from 'iso-639-1'
-import { u64 } from '@polkadot/types/primitive'
-import { FindConditions } from 'typeorm'
-import * as jspb from 'google-protobuf'
-import { fixBlockTimestamp } from '../eventFix'
-
-// protobuf definitions
-import {
-  ChannelMetadata,
-  ChannelCategoryMetadata,
-  PublishedBeforeJoystream as PublishedBeforeJoystreamMetadata,
-  License as LicenseMetadata,
-  MediaType as MediaTypeMetadata,
-  VideoMetadata,
-  VideoCategoryMetadata,
-} from '@joystream/content-metadata-protobuf'
-
-import { Content } from '../../../generated/types'
-
-import { invalidMetadata, inconsistentState, logger, prepareDataObject, getNextId } from '../common'
-
-import {
-  // primary entities
-  CuratorGroup,
-  Channel,
-  ChannelCategory,
-  Video,
-  VideoCategory,
-
-  // secondary entities
-  Language,
-  License,
-  VideoMediaEncoding,
-  VideoMediaMetadata,
-
-  // asset
-  DataObjectOwner,
-  DataObjectOwnerMember,
-  DataObjectOwnerChannel,
-  DataObject,
-  LiaisonJudgement,
-  AssetAvailability,
-  Membership,
-} from 'query-node'
-
-// Joystream types
-import { ChannelId, ContentParameters, NewAsset, ContentActor } from '@joystream/types/augment'
-
-import { ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
-import { registry } from '@joystream/types'
-
-/*
-  Asset either stored in storage or describing list of URLs.
-*/
-type AssetStorageOrUrls = DataObject | string[]
-
-/*
-  Type guard differentiating asset stored in storage from asset describing a list of URLs.
-*/
-function isAssetInStorage(dataObject: AssetStorageOrUrls): dataObject is DataObject {
-  if (Array.isArray(dataObject)) {
-    return false
-  }
-
-  return true
-}
-
-export interface IReadProtobufArguments {
-  metadata: Bytes
-  db: DatabaseManager
-  event: SubstrateEvent
-}
-
-export interface IReadProtobufArgumentsWithAssets extends IReadProtobufArguments {
-  assets: NewAsset[] // assets provided in event
-  contentOwner: typeof DataObjectOwner
-}
-
-/*
-  This class represents one of 3 possible states when changing property read from metadata.
-  NoChange - don't change anything (used when invalid metadata are encountered)
-  Unset - unset the value (used when the unset is requested in runtime)
-  Change - set the new value
-*/
-export class PropertyChange<T> {
-  static newUnset<T>(): PropertyChange<T> {
-    return new PropertyChange<T>('unset')
-  }
-
-  static newNoChange<T>(): PropertyChange<T> {
-    return new PropertyChange<T>('nochange')
-  }
-
-  static newChange<T>(value: T): PropertyChange<T> {
-    return new PropertyChange<T>('change', value)
-  }
-
-  /*
-    Determines property change from the given object property.
-  */
-  static fromObjectProperty<T, Key extends string, ChangedObject extends { [key in Key]?: T }>(
-    object: ChangedObject,
-    key: Key
-  ): PropertyChange<T> {
-    if (!(key in object)) {
-      return PropertyChange.newNoChange<T>()
-    }
-
-    if (object[key] === undefined) {
-      return PropertyChange.newUnset<T>()
-    }
-
-    return PropertyChange.newChange<T>(object[key] as T)
-  }
-
-  private type: string
-  private value?: T
-
-  private constructor(type: 'change' | 'nochange' | 'unset', value?: T) {
-    this.type = type
-    this.value = value
-  }
-
-  public isUnset(): boolean {
-    return this.type === 'unset'
-  }
-
-  public isNoChange(): boolean {
-    return this.type === 'nochange'
-  }
-
-  public isValue(): boolean {
-    return this.type === 'change'
-  }
-
-  public getValue(): T | undefined {
-    return this.type === 'change' ? this.value : undefined
-  }
-
-  /*
-    Integrates the value into the given dictionary.
-  */
-  public integrateInto(object: Object, key: string): void {
-    if (this.isNoChange()) {
-      return
-    }
-
-    if (this.isUnset()) {
-      delete object[key]
-      return
-    }
-
-    object[key] = this.value
-  }
-}
-
-export interface RawVideoMetadata {
-  encoding: {
-    codecName: PropertyChange<string>
-    container: PropertyChange<string>
-    mimeMediaType: PropertyChange<string>
-  }
-  pixelWidth: PropertyChange<number>
-  pixelHeight: PropertyChange<number>
-  size: PropertyChange<number>
-}
-
-/*
-  Reads information from the event and protobuf metadata and constructs changeset that's fit to be used when saving to db.
-*/
-export async function readProtobuf<T extends ChannelCategory | VideoCategory>(
-  type: T,
-  parameters: IReadProtobufArguments
-): Promise<Partial<T>> {
-  // true option here is crucial, it indicates that we want just the underlying bytes (by default it will also include bytes encoding the length)
-  const metaU8a = parameters.metadata.toU8a(true)
-
-  // process channel category
-  if (type instanceof ChannelCategory) {
-    const meta = ChannelCategoryMetadata.deserializeBinary(metaU8a)
-    const result = convertMetadataToObject<ChannelCategoryMetadata.AsObject>(meta) as Partial<T>
-
-    return result
-  }
-
-  // process video category
-  if (type instanceof VideoCategory) {
-    const meta = VideoCategoryMetadata.deserializeBinary(metaU8a)
-    const result = convertMetadataToObject<VideoCategoryMetadata.AsObject>(meta) as Partial<T>
-
-    return result
-  }
-
-  // this should never happen
-  logger.error('Not implemented metadata type', { type })
-  throw new Error(`Not implemented metadata type`)
-}
-
-/*
-  Reads information from the event and protobuf metadata and constructs changeset that's fit to be used when saving to db.
-  In addition it handles any assets associated with the metadata.
-*/
-
-export async function readProtobufWithAssets<T extends Channel | Video>(
-  type: T,
-  parameters: IReadProtobufArgumentsWithAssets
-): Promise<Partial<T>> {
-  // true option here is crucial, it indicates that we want just the underlying bytes (by default it will also include bytes encoding the length)
-  const metaU8a = parameters.metadata.toU8a(true)
-
-  // process channel
-  if (type instanceof Channel) {
-    const meta = ChannelMetadata.deserializeBinary(metaU8a)
-    const metaAsObject = convertMetadataToObject<ChannelMetadata.AsObject>(meta)
-    const result = (metaAsObject as any) as Partial<Channel>
-
-    // prepare cover photo asset if needed
-    if ('coverPhoto' in metaAsObject) {
-      const asset = await extractAsset({
-        assetIndex: metaAsObject.coverPhoto,
-        assets: parameters.assets,
-        db: parameters.db,
-        event: parameters.event,
-        contentOwner: parameters.contentOwner,
-      })
-      integrateAsset('coverPhoto', result, asset) // changes `result` inline!
-      delete metaAsObject.coverPhoto
-    }
-
-    // prepare avatar photo asset if needed
-    if ('avatarPhoto' in metaAsObject) {
-      const asset = await extractAsset({
-        assetIndex: metaAsObject.avatarPhoto,
-        assets: parameters.assets,
-        db: parameters.db,
-        event: parameters.event,
-        contentOwner: parameters.contentOwner,
-      })
-      integrateAsset('avatarPhoto', result, asset) // changes `result` inline!
-      delete metaAsObject.avatarPhoto
-    }
-
-    // prepare language if needed
-    if ('language' in metaAsObject) {
-      const language = await prepareLanguage(metaAsObject.language, parameters.db, parameters.event)
-      delete metaAsObject.language // make sure temporary value will not interfere
-      language.integrateInto(result, 'language')
-    }
-
-    return result as Partial<T>
-  }
-
-  // process video
-  if (type instanceof Video) {
-    const meta = VideoMetadata.deserializeBinary(metaU8a)
-    const metaAsObject = convertMetadataToObject<VideoMetadata.AsObject>(meta)
-    const result = (metaAsObject as any) as Partial<Video>
-
-    // prepare video category if needed
-    if ('category' in metaAsObject) {
-      const category = await prepareVideoCategory(metaAsObject.category, parameters.db)
-      delete metaAsObject.category // make sure temporary value will not interfere
-      category.integrateInto(result, 'category')
-    }
-
-    // prepare media meta information if needed
-    if ('mediaType' in metaAsObject || 'mediaPixelWidth' in metaAsObject || 'mediaPixelHeight' in metaAsObject) {
-      // prepare video file size if poosible
-      const videoSize = extractVideoSize(parameters.assets, metaAsObject.video)
-
-      // NOTE: type hack - `RawVideoMetadata` is inserted instead of VideoMediaMetadata - it should be edited in `video.ts`
-      //       see `integrateVideoMetadata()` in `video.ts` for more info
-      result.mediaMetadata = (prepareVideoMetadata(
-        metaAsObject,
-        videoSize,
-        parameters.event.blockNumber
-      ) as unknown) as VideoMediaMetadata
-
-      // remove extra values
-      delete metaAsObject.mediaType
-      delete metaAsObject.mediaPixelWidth
-      delete metaAsObject.mediaPixelHeight
-    }
-
-    // prepare license if needed
-    if ('license' in metaAsObject) {
-      result.license = await prepareLicense(parameters.db, metaAsObject.license, parameters.event)
-    }
-
-    // prepare thumbnail photo asset if needed
-    if ('thumbnailPhoto' in metaAsObject) {
-      const asset = await extractAsset({
-        assetIndex: metaAsObject.thumbnailPhoto,
-        assets: parameters.assets,
-        db: parameters.db,
-        event: parameters.event,
-        contentOwner: parameters.contentOwner,
-      })
-      integrateAsset('thumbnailPhoto', result, asset) // changes `result` inline!
-      delete metaAsObject.thumbnailPhoto
-    }
-
-    // prepare video asset if needed
-    if ('video' in metaAsObject) {
-      const asset = await extractAsset({
-        assetIndex: metaAsObject.video,
-        assets: parameters.assets,
-        db: parameters.db,
-        event: parameters.event,
-        contentOwner: parameters.contentOwner,
-      })
-      integrateAsset('media', result, asset) // changes `result` inline!
-      delete metaAsObject.video
-    }
-
-    // prepare language if needed
-    if ('language' in metaAsObject) {
-      const language = await prepareLanguage(metaAsObject.language, parameters.db, parameters.event)
-      delete metaAsObject.language // make sure temporary value will not interfere
-      language.integrateInto(result, 'language')
-    }
-
-    if (metaAsObject.publishedBeforeJoystream) {
-      const publishedBeforeJoystream = handlePublishedBeforeJoystream(result, metaAsObject.publishedBeforeJoystream)
-      delete metaAsObject.publishedBeforeJoystream // make sure temporary value will not interfere
-      publishedBeforeJoystream.integrateInto(result, 'publishedBeforeJoystream')
-    }
-
-    return result as Partial<T>
-  }
-
-  // this should never happen
-  logger.error('Not implemented metadata type', { type })
-  throw new Error(`Not implemented metadata type`)
-}
-
-export async function convertContentActorToChannelOwner(
-  db: DatabaseManager,
-  contentActor: ContentActor
-): Promise<{
-  ownerMember?: Membership
-  ownerCuratorGroup?: CuratorGroup
-}> {
-  if (contentActor.isMember) {
-    const memberId = contentActor.asMember.toNumber()
-    const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
-
-    // ensure member exists
-    if (!member) {
-      return inconsistentState(`Actor is non-existing member`, memberId)
-    }
-
-    return {
-      ownerMember: member,
-      ownerCuratorGroup: undefined, // this will clear the field
-    }
-  }
-
-  if (contentActor.isCurator) {
-    const curatorGroupId = contentActor.asCurator[0].toNumber()
-    const curatorGroup = await db.get(CuratorGroup, {
-      where: { id: curatorGroupId.toString() } as FindConditions<CuratorGroup>,
-    })
-
-    // ensure curator group exists
-    if (!curatorGroup) {
-      return inconsistentState('Actor is non-existing curator group', curatorGroupId)
-    }
-
-    return {
-      ownerMember: undefined, // this will clear the field
-      ownerCuratorGroup: curatorGroup,
-    }
-  }
-
-  // TODO: contentActor.isLead
-
-  logger.error('Not implemented ContentActor type', { contentActor: contentActor.toString() })
-  throw new Error('Not-implemented ContentActor type used')
-}
-
-export function convertContentActorToDataObjectOwner(
-  contentActor: ContentActor,
-  channelId: number
-): typeof DataObjectOwner {
-  const owner = new DataObjectOwnerChannel()
-  owner.channel = channelId
-
-  return owner
-
-  /* contentActor is irrelevant now -> all video/channel content belongs to the channel
-  if (contentActor.isMember) {
-    const owner = new DataObjectOwnerMember()
-    owner.member = contentActor.asMember.toBn()
-
-    return owner
-  }
-
-  if (contentActor.isLead || contentActor.isCurator) {
-    const owner = new DataObjectOwnerChannel()
-    owner.channel = channelId
-
-    return owner
-  }
-
-  logger.error('Not implemented ContentActor type', {contentActor: contentActor.toString()})
-  throw new Error('Not-implemented ContentActor type used')
-  */
-}
-
-function handlePublishedBeforeJoystream(
-  video: Partial<Video>,
-  metadata: PublishedBeforeJoystreamMetadata.AsObject
-): PropertyChange<Date> {
-  // is publish being unset
-  if ('isPublished' in metadata && !metadata.isPublished) {
-    return PropertyChange.newUnset()
-  }
-
-  // try to parse timestamp from publish date
-  const timestamp = metadata.date ? Date.parse(metadata.date) : NaN
-
-  // ensure date is valid
-  if (isNaN(timestamp)) {
-    invalidMetadata(`Invalid date used for publishedBeforeJoystream`, {
-      timestamp,
-    })
-    return PropertyChange.newNoChange()
-  }
-
-  // set new date
-  return PropertyChange.newChange(new Date(timestamp))
-}
-
-interface IConvertAssetParameters {
-  rawAsset: NewAsset
-  db: DatabaseManager
-  event: SubstrateEvent
-  contentOwner: typeof DataObjectOwner
-}
-
-/*
-  Converts event asset into data object or list of URLs fit to be saved to db.
-*/
-async function convertAsset(parameters: IConvertAssetParameters): Promise<AssetStorageOrUrls> {
-  // is asset describing list of URLs?
-  if (parameters.rawAsset.isUrls) {
-    const urls = parameters.rawAsset.asUrls.toArray().map((item) => item.toString())
-
-    return urls
-  }
-
-  // !parameters.rawAsset.isUrls && parameters.rawAsset.isUpload // asset is in storage
-
-  // prepare data object
-  const contentParameters: ContentParameters = parameters.rawAsset.asUpload
-  const dataObject = await prepareDataObject(
-    parameters.db,
-    contentParameters,
-    parameters.event,
-    parameters.contentOwner
-  )
-
-  return dataObject
-}
-
-interface IExtractAssetParameters {
-  assetIndex: number | undefined
-  assets: NewAsset[]
-  db: DatabaseManager
-  event: SubstrateEvent
-  contentOwner: typeof DataObjectOwner
-}
-
-/*
-  Selects asset from provided set of assets and prepares asset data fit to be saved to db.
-*/
-async function extractAsset(parameters: IExtractAssetParameters): Promise<PropertyChange<AssetStorageOrUrls>> {
-  // is asset being unset?
-  if (parameters.assetIndex === undefined) {
-    return PropertyChange.newUnset()
-  }
-
-  // ensure asset index is valid
-  if (parameters.assetIndex >= parameters.assets.length) {
-    invalidMetadata(`Non-existing asset extraction requested`, {
-      assetsProvided: parameters.assets.length,
-      assetIndex: parameters.assetIndex,
-    })
-    return PropertyChange.newNoChange()
-  }
-
-  // convert asset to data object record
-  const asset = await convertAsset({
-    rawAsset: parameters.assets[parameters.assetIndex],
-    db: parameters.db,
-    event: parameters.event,
-    contentOwner: parameters.contentOwner,
-  })
-
-  return PropertyChange.newChange(asset)
-}
-
-/*
-  As a temporary messure to overcome yet-to-be-implemented features in Hydra, we are using redudant information
-  to describe asset state. This function introduces all redudant data needed to be saved to db.
-
-  Changes `result` argument!
-*/
-function integrateAsset<T>(propertyName: string, result: Object, asset: PropertyChange<AssetStorageOrUrls>): void {
-  // helpers - property names
-  const nameUrl = propertyName + 'Urls'
-  const nameDataObject = propertyName + 'DataObject'
-  const nameAvailability = propertyName + 'Availability'
-
-  if (asset.isNoChange()) {
-    return
-  }
-
-  if (asset.isUnset()) {
-    result[nameUrl] = []
-    result[nameAvailability] = AssetAvailability.INVALID
-    result[nameDataObject] = undefined // plan deletion (will have effect when saved to db)
-
-    return
-  }
-
-  const newValue = asset.getValue() as AssetStorageOrUrls
-
-  // is asset available on external URL(s)
-  if (!isAssetInStorage(newValue)) {
-    // (un)set asset's properties
-    result[nameUrl] = newValue
-    result[nameAvailability] = AssetAvailability.ACCEPTED
-    result[nameDataObject] = undefined // plan deletion (will have effect when saved to db)
-
-    return
-  }
-
-  // asset saved in storage
-
-  // prepare conversion table between liaison judgment and asset availability
-  const conversionTable = {
-    [LiaisonJudgement.ACCEPTED]: AssetAvailability.ACCEPTED,
-    [LiaisonJudgement.PENDING]: AssetAvailability.PENDING,
-  }
-
-  // (un)set asset's properties
-  result[nameUrl] = [] // plan deletion (will have effect when saved to db)
-  result[nameAvailability] = conversionTable[newValue.liaisonJudgement]
-  result[nameDataObject] = newValue
-}
-
-function extractVideoSize(assets: NewAsset[], assetIndex: number | undefined): number | undefined {
-  // escape if no asset is required
-  if (assetIndex === undefined) {
-    return undefined
-  }
-
-  // ensure asset index is valid
-  if (assetIndex > assets.length) {
-    invalidMetadata(`Non-existing asset video size extraction requested`, { assetsProvided: assets.length, assetIndex })
-    return undefined
-  }
-
-  const rawAsset = assets[assetIndex]
-
-  // escape if asset is describing URLs (can't get size)
-  if (rawAsset.isUrls) {
-    return undefined
-  }
-
-  // !rawAsset.isUrls && rawAsset.isUpload // asset is in storage
-
-  // convert generic content parameters coming from processor to custom Joystream data type
-  const customContentParameters = new Custom_ContentParameters(registry, rawAsset.asUpload.toJSON() as any)
-  // extract video size
-  const videoSize = customContentParameters.size_in_bytes.toNumber()
-
-  return videoSize
-}
-
-async function prepareLanguage(
-  languageIso: string | undefined,
-  db: DatabaseManager,
-  event: SubstrateEvent
-): Promise<PropertyChange<Language>> {
-  // is language being unset?
-  if (languageIso === undefined) {
-    return PropertyChange.newUnset()
-  }
-
-  // validate language string
-  const isValidIso = ISO6391.validate(languageIso)
-
-  // ensure language string is valid
-  if (!isValidIso) {
-    invalidMetadata(`Invalid language ISO-639-1 provided`, languageIso)
-    return PropertyChange.newNoChange()
-  }
-
-  // load language
-  const language = await db.get(Language, { where: { iso: languageIso } as FindConditions<Language> })
-
-  // return existing language if any
-  if (language) {
-    return PropertyChange.newChange(language)
-  }
-
-  // create new language
-  const newLanguage = new Language({
-    // set id as iso to overcome current graphql filtering limitations (so we can use query `videos(where: {languageId_eq: 'en'})`)
-    // id: await getNextId(db),
-    id: languageIso,
-    iso: languageIso,
-    createdInBlock: event.blockNumber,
-
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    // TODO: remove these lines after Hydra auto-fills the values when cascading save (remove them on all places)
-    createdById: '1',
-    updatedById: '1',
-  })
-
-  await db.save<Language>(newLanguage)
-
-  return PropertyChange.newChange(newLanguage)
-}
-
-async function prepareLicense(
-  db: DatabaseManager,
-  licenseProtobuf: LicenseMetadata.AsObject | undefined,
-  event: SubstrateEvent
-): Promise<License | undefined> {
-  // NOTE: Deletion of any previous license should take place in appropriate event handling function
-  //       and not here even it might appear so.
-
-  // is license being unset?
-  if (licenseProtobuf === undefined) {
-    return undefined
-  }
-
-  // license is meant to be deleted
-  if (isLicenseEmpty(licenseProtobuf)) {
-    return new License({})
-  }
-
-  // crete new license
-  const license = new License({
-    ...licenseProtobuf,
-    id: await getNextId(db),
-
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    createdById: '1',
-    updatedById: '1',
-  })
-
-  return license
-}
-
-/*
-  Checks if protobof contains license with some fields filled or is empty object (`{}` or `{someKey: undefined, ...}`).
-  Empty object means deletion is requested.
-*/
-function isLicenseEmpty(licenseObject: LicenseMetadata.AsObject): boolean {
-  const somePropertySet = Object.entries(licenseObject).reduce((acc, [key, value]) => {
-    return acc || value !== undefined
-  }, false)
-
-  return !somePropertySet
-}
-
-function prepareVideoMetadata(
-  videoProtobuf: VideoMetadata.AsObject,
-  videoSize: number | undefined,
-  blockNumber: number
-): RawVideoMetadata {
-  const rawMeta = {
-    encoding: {
-      codecName: PropertyChange.fromObjectProperty<string, 'codecName', MediaTypeMetadata.AsObject>(
-        videoProtobuf.mediaType || {},
-        'codecName'
-      ),
-      container: PropertyChange.fromObjectProperty<string, 'container', MediaTypeMetadata.AsObject>(
-        videoProtobuf.mediaType || {},
-        'container'
-      ),
-      mimeMediaType: PropertyChange.fromObjectProperty<string, 'mimeMediaType', MediaTypeMetadata.AsObject>(
-        videoProtobuf.mediaType || {},
-        'mimeMediaType'
-      ),
-    },
-    pixelWidth: PropertyChange.fromObjectProperty<number, 'mediaPixelWidth', VideoMetadata.AsObject>(
-      videoProtobuf,
-      'mediaPixelWidth'
-    ),
-    pixelHeight: PropertyChange.fromObjectProperty<number, 'mediaPixelHeight', VideoMetadata.AsObject>(
-      videoProtobuf,
-      'mediaPixelHeight'
-    ),
-    size: videoSize === undefined ? PropertyChange.newNoChange() : PropertyChange.newChange(videoSize),
-  } as RawVideoMetadata
-
-  return rawMeta
-}
-
-async function prepareVideoCategory(
-  categoryId: number | undefined,
-  db: DatabaseManager
-): Promise<PropertyChange<VideoCategory>> {
-  // is category being unset?
-  if (categoryId === undefined) {
-    return PropertyChange.newUnset()
-  }
-
-  // load video category
-  const category = await db.get(VideoCategory, {
-    where: { id: categoryId.toString() } as FindConditions<VideoCategory>,
-  })
-
-  // ensure video category exists
-  if (!category) {
-    invalidMetadata('Non-existing video category association with video requested', categoryId)
-    return PropertyChange.newNoChange()
-  }
-
-  return PropertyChange.newChange(category)
-}
-
-function convertMetadataToObject<T extends Object>(metadata: jspb.Message): T {
-  const metaAsObject = metadata.toObject()
-  const result = {} as T
-
-  for (const key in metaAsObject) {
-    const funcNameBase = key.charAt(0).toUpperCase() + key.slice(1)
-    const hasFuncName = 'has' + funcNameBase
-    const isSet =
-      funcNameBase === 'PersonsList' // there is no `VideoMetadata.hasPersonsList` method from unkown reason -> create exception
-        ? true
-        : metadata[hasFuncName]()
-
-    if (!isSet) {
-      continue
-    }
-
-    const getFuncName = 'get' + funcNameBase
-    const value = metadata[getFuncName]()
-
-    // TODO: check that recursion trully works
-    if (value instanceof jspb.Message) {
-      result[key] = convertMetadataToObject(value)
-      continue
-    }
-
-    result[key] = metaAsObject[key]
-  }
-
-  return result
-}

+ 0 - 498
query-node/mappings/sumer/content/video.ts

@@ -1,498 +0,0 @@
-import BN from 'bn.js'
-import { fixBlockTimestamp } from '../eventFix'
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { FindConditions, In } from 'typeorm'
-
-import { Content } from '../../../generated/types'
-
-import { inconsistentState, logger, getNextId } from '../common'
-
-import { convertContentActorToDataObjectOwner, readProtobuf, readProtobufWithAssets, RawVideoMetadata } from './utils'
-
-import {
-  AssetAvailability,
-  Channel,
-  License,
-  Video,
-  VideoCategory,
-  VideoMediaEncoding,
-  VideoMediaMetadata,
-} from 'query-node'
-
-// Joystream types
-import { ChannelId } from '@joystream/types/augment'
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoCategoryCreated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoCategoryId, videoCategoryCreationParameters, contentActor } = new Content.VideoCategoryCreatedEvent(
-    event
-  ).data
-
-  // read metadata
-  const protobufContent = await readProtobuf(new VideoCategory(), {
-    metadata: videoCategoryCreationParameters.meta,
-    db,
-    event,
-  })
-
-  // create new video category
-  const videoCategory = new VideoCategory({
-    // main data
-    id: videoCategoryId.toString(),
-    videos: [],
-    createdInBlock: event.blockNumber,
-
-    // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    // integrate metadata
-    ...protobufContent,
-  })
-
-  // save video category
-  await db.save<VideoCategory>(videoCategory)
-
-  // emit log event
-  logger.info('Video category has been created', { id: videoCategoryId })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoCategoryUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoCategoryId, videoCategoryUpdateParameters, contentActor } = new Content.VideoCategoryUpdatedEvent(
-    event
-  ).data
-
-  // load video category
-  const videoCategory = await db.get(VideoCategory, {
-    where: { id: videoCategoryId.toString() } as FindConditions<VideoCategory>,
-  })
-
-  // ensure video category exists
-  if (!videoCategory) {
-    return inconsistentState('Non-existing video category update requested', videoCategoryId)
-  }
-
-  // read metadata
-  const protobufContent = await readProtobuf(new VideoCategory(), {
-    metadata: videoCategoryUpdateParameters.new_meta,
-    db,
-    event,
-  })
-
-  // update all fields read from protobuf
-  for (const [key, value] of Object.entries(protobufContent)) {
-    videoCategory[key] = value
-  }
-
-  // set last update time
-  videoCategory.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save video category
-  await db.save<VideoCategory>(videoCategory)
-
-  // emit log event
-  logger.info('Video category has been updated', { id: videoCategoryId })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoCategoryDeleted(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoCategoryId } = new Content.VideoCategoryDeletedEvent(event).data
-
-  // load video category
-  const videoCategory = await db.get(VideoCategory, {
-    where: { id: videoCategoryId.toString() } as FindConditions<VideoCategory>,
-  })
-
-  // ensure video category exists
-  if (!videoCategory) {
-    return inconsistentState('Non-existing video category deletion requested', videoCategoryId)
-  }
-
-  // remove video category
-  await db.remove<VideoCategory>(videoCategory)
-
-  // emit log event
-  logger.info('Video category has been deleted', { id: videoCategoryId })
-}
-
-/// ///////////////// Video //////////////////////////////////////////////////////
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoCreated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { channelId, videoId, videoCreationParameters, contentActor } = new Content.VideoCreatedEvent(event).data
-
-  // read metadata
-  const protobufContent = await readProtobufWithAssets(new Video(), {
-    metadata: videoCreationParameters.meta,
-    db,
-    event,
-    assets: videoCreationParameters.assets,
-    contentOwner: convertContentActorToDataObjectOwner(contentActor, channelId.toNumber()),
-  })
-
-  // load channel
-  const channel = await db.get(Channel, { where: { id: channelId.toString() } as FindConditions<Channel> })
-
-  // ensure channel exists
-  if (!channel) {
-    return inconsistentState('Trying to add video to non-existing channel', channelId)
-  }
-
-  // prepare video media metadata (if any)
-  const fixedProtobuf = await integrateVideoMediaMetadata(db, null, protobufContent, event)
-
-  const licenseIsEmpty = fixedProtobuf.license && !Object.keys(fixedProtobuf.license).length
-  if (licenseIsEmpty) {
-    // license deletion was requested - ignore it and consider it empty
-    delete fixedProtobuf.license
-  }
-
-  // create new video
-  const video = new Video({
-    // main data
-    id: videoId.toString(),
-    isCensored: false,
-    channel,
-    createdInBlock: event.blockNumber,
-    isFeatured: false,
-
-    // default values for properties that might or might not be filled by metadata
-    thumbnailPhotoUrls: [],
-    thumbnailPhotoAvailability: AssetAvailability.INVALID,
-    mediaUrls: [],
-    mediaAvailability: AssetAvailability.INVALID,
-
-    // fill in auto-generated fields
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-
-    // integrate metadata
-    ...fixedProtobuf,
-  })
-
-  // save video
-  await db.save<Video>(video)
-
-  // emit log event
-  logger.info('Video has been created', { id: videoId })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoId, videoUpdateParameters, contentActor } = new Content.VideoUpdatedEvent(event).data
-
-  // load video
-  const video = await db.get(Video, {
-    where: { id: videoId.toString() } as FindConditions<Video>,
-    relations: ['channel', 'license'],
-  })
-
-  // ensure video exists
-  if (!video) {
-    return inconsistentState('Non-existing video update requested', videoId)
-  }
-
-  // prepare changed metadata
-  const newMetadata = videoUpdateParameters.new_meta.unwrapOr(null)
-
-  // license must be deleted AFTER video is saved - plan a license deletion by assigning it to this variable
-  let licenseToDelete: License | null = null
-
-  // update metadata if it was changed
-  if (newMetadata) {
-    const protobufContent = await readProtobufWithAssets(new Video(), {
-      metadata: newMetadata,
-      db,
-      event,
-      assets: videoUpdateParameters.assets.unwrapOr([]),
-      contentOwner: convertContentActorToDataObjectOwner(contentActor, new BN(video.channel.id).toNumber()),
-    })
-
-    // prepare video media metadata (if any)
-    const fixedProtobuf = await integrateVideoMediaMetadata(db, video, protobufContent, event)
-
-    // remember original license
-    const originalLicense = video.license
-
-    // update all fields read from protobuf
-    for (const [key, value] of Object.entries(fixedProtobuf)) {
-      video[key] = value
-    }
-
-    // license has changed - plan old license delete
-    if (originalLicense && video.license !== originalLicense) {
-      ;[video.license, licenseToDelete] = handleLicenseUpdate(originalLicense, video.license)
-    } else if (!Object.keys(video.license || {}).length) {
-      // license deletion was requested event no license exists?
-      delete video.license // ensure license is empty
-    }
-  }
-
-  // set last update time
-  video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save video
-  await db.save<Video>(video)
-
-  // delete old license if it's planned
-  if (licenseToDelete) {
-    await db.remove<License>(licenseToDelete)
-  }
-
-  // emit log event
-  logger.info('Video has been updated', { id: videoId })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoDeleted(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoId } = new Content.VideoDeletedEvent(event).data
-
-  // load video
-  const video = await db.get(Video, { where: { id: videoId.toString() } as FindConditions<Video> })
-
-  // ensure video exists
-  if (!video) {
-    return inconsistentState('Non-existing video deletion requested', videoId)
-  }
-
-  // remove video
-  await db.remove<Video>(video)
-
-  // emit log event
-  logger.info('Video has been deleted', { id: videoId })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_VideoCensorshipStatusUpdated(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoId, isCensored } = new Content.VideoCensorshipStatusUpdatedEvent(event).data
-
-  // load video
-  const video = await db.get(Video, { where: { id: videoId.toString() } as FindConditions<Video> })
-
-  // ensure video exists
-  if (!video) {
-    return inconsistentState('Non-existing video censoring requested', videoId)
-  }
-
-  // update video
-  video.isCensored = isCensored.isTrue
-
-  // set last update time
-  video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save video
-  await db.save<Video>(video)
-
-  // emit log event
-  logger.info('Video censorship status has been updated', { id: videoId, isCensored: isCensored.isTrue })
-}
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export async function content_FeaturedVideosSet(db: DatabaseManager, event: SubstrateEvent) {
-  // read event data
-  const { videoId: videoIds } = new Content.FeaturedVideosSetEvent(event).data
-
-  // load old featured videos
-  const existingFeaturedVideos = await db.getMany(Video, { where: { isFeatured: true } as FindConditions<Video> })
-
-  // comparsion utility
-  const isSame = (videoIdA: string) => (videoIdB: string) => videoIdA === videoIdB
-
-  // calculate diff sets
-  const toRemove = existingFeaturedVideos.filter(
-    (existingFV) => !videoIds.map((item) => item.toString()).some(isSame(existingFV.id))
-  )
-  const toAdd = videoIds.filter(
-    (video) => !existingFeaturedVideos.map((item) => item.id).some(isSame(video.toString()))
-  )
-
-  // escape if no featured video needs to be added or removed
-  if (!toRemove.length && !toAdd.length) {
-    // emit log event
-    logger.info('Featured videos unchanged')
-
-    return
-  }
-
-  // mark previously featured videos as not-featured
-  await Promise.all(
-    toRemove.map(async (video) => {
-      video.isFeatured = false
-
-      // set last update time
-      video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-      await db.save<Video>(video)
-    })
-  )
-
-  // escape if no featured video needs to be added
-  if (!toAdd.length) {
-    // emit log event
-    logger.info('Some featured videos have been unset.', { videoIds: toRemove.map((item) => item.id.toString()) })
-
-    return
-  }
-
-  // read videos previously not-featured videos that are meant to be featured
-  const videosToAdd = await db.getMany(Video, {
-    where: {
-      id: In(toAdd.map((item) => item.toString())),
-    } as FindConditions<Video>,
-  })
-
-  if (videosToAdd.length !== toAdd.length) {
-    return inconsistentState('At least one non-existing video featuring requested', toAdd)
-  }
-
-  // mark previously not-featured videos as featured
-  await Promise.all(
-    videosToAdd.map(async (video) => {
-      video.isFeatured = true
-
-      // set last update time
-      video.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-      await db.save<Video>(video)
-    })
-  )
-
-  // emit log event
-  logger.info('New featured videos have been set', { videoIds })
-}
-
-/// ///////////////// Helpers ////////////////////////////////////////////////////
-
-/*
-  Integrates video metadata-related data into existing data (if any) or creates a new record.
-
-  NOTE: type hack - `RawVideoMetadata` is accepted for `metadata` instead of `Partial<Video>`
-        see `prepareVideoMetadata()` in `utils.ts` for more info
-*/
-async function integrateVideoMediaMetadata(
-  db: DatabaseManager,
-  existingRecord: Video | null,
-  metadata: Partial<Video>,
-  event: SubstrateEvent
-): Promise<Partial<Video>> {
-  if (!metadata.mediaMetadata) {
-    return metadata
-  }
-
-  const now = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // fix TS type
-  const rawMediaMetadata = (metadata.mediaMetadata as unknown) as RawVideoMetadata
-
-  // ensure encoding object
-  const encoding =
-    (existingRecord && existingRecord.mediaMetadata && existingRecord.mediaMetadata.encoding) ||
-    new VideoMediaEncoding({
-      createdAt: now,
-      updatedAt: now,
-
-      createdById: '1',
-      updatedById: '1',
-    })
-
-  // integrate media encoding-related data
-  rawMediaMetadata.encoding.codecName.integrateInto(encoding, 'codecName')
-  rawMediaMetadata.encoding.container.integrateInto(encoding, 'container')
-  rawMediaMetadata.encoding.mimeMediaType.integrateInto(encoding, 'mimeMediaType')
-
-  // ensure media metadata object
-  const mediaMetadata =
-    (existingRecord && existingRecord.mediaMetadata) ||
-    new VideoMediaMetadata({
-      createdInBlock: event.blockNumber,
-
-      createdAt: now,
-      updatedAt: now,
-
-      createdById: '1',
-      updatedById: '1',
-    })
-
-  // integrate media-related data
-  rawMediaMetadata.pixelWidth.integrateInto(mediaMetadata, 'pixelWidth')
-  rawMediaMetadata.pixelHeight.integrateInto(mediaMetadata, 'pixelHeight')
-  rawMediaMetadata.size.integrateInto(mediaMetadata, 'size')
-
-  // connect encoding to media metadata object
-  mediaMetadata.encoding = encoding
-
-  // ensure predictable ids
-  if (!mediaMetadata.encoding.id) {
-    mediaMetadata.encoding.id = await getNextId(db)
-  }
-  if (!mediaMetadata.id) {
-    mediaMetadata.id = await getNextId(db)
-  }
-
-  /// ///////////////// update updatedAt if needed ///////////////////////////////
-
-  const encodingNoChange =
-    true &&
-    rawMediaMetadata.encoding.codecName.isNoChange() &&
-    rawMediaMetadata.encoding.container.isNoChange() &&
-    rawMediaMetadata.encoding.mimeMediaType.isNoChange()
-  const mediaMetadataNoChange =
-    encodingNoChange &&
-    rawMediaMetadata.encoding.codecName.isNoChange() &&
-    rawMediaMetadata.encoding.container.isNoChange() &&
-    rawMediaMetadata.encoding.mimeMediaType.isNoChange()
-
-  if (!encodingNoChange) {
-    // encoding changed?
-    mediaMetadata.encoding.updatedAt = now
-  }
-  if (!mediaMetadataNoChange) {
-    // metadata changed?
-    mediaMetadata.updatedAt = now
-  }
-
-  /// ////////////////////////////////////////////////////////////////////////////
-
-  return {
-    ...metadata,
-    mediaMetadata,
-  }
-}
-
-// returns tuple `[newLicenseForVideo, oldLicenseToBeDeleted]`
-function handleLicenseUpdate(originalLicense, newLicense): [License | undefined, License | null] {
-  const isNewEmpty = !Object.keys(newLicense).length
-
-  if (!originalLicense && isNewEmpty) {
-    return [undefined, null]
-  }
-
-  if (!originalLicense) {
-    // && !isNewEmpty
-    return [newLicense, null]
-  }
-
-  if (!isNewEmpty) {
-    // && originalLicense
-    return [
-      new License({
-        ...originalLicense,
-        ...newLicense,
-      }),
-      null,
-    ]
-  }
-
-  // originalLicense && isNewEmpty
-
-  return [originalLicense, null]
-}

+ 0 - 6
query-node/mappings/sumer/eventFix.ts

@@ -1,6 +0,0 @@
-import BN from 'bn.js'
-
-// Workaround for https://github.com/Joystream/hydra/issues/326 . This file can be removed after it's fixed
-export function fixBlockTimestamp(blockTimestamp: unknown): BN {
-  return new BN(blockTimestamp as string)
-}

+ 0 - 280
query-node/mappings/sumer/storage.ts

@@ -1,280 +0,0 @@
-import { fixBlockTimestamp } from './eventFix'
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { FindConditions, In } from 'typeorm'
-
-import { inconsistentState, logger, prepareDataObject } from './common'
-
-import { DataDirectory } from '../../generated/types'
-import { ContentId, ContentParameters, StorageObjectOwner } from '@joystream/types/augment'
-
-import { ContentId as Custom_ContentId, ContentParameters as Custom_ContentParameters } from '@joystream/types/storage'
-import { registry } from '@joystream/types'
-
-import {
-  Channel,
-  Video,
-  AssetAvailability,
-  DataObject,
-  DataObjectOwner,
-  DataObjectOwnerMember,
-  DataObjectOwnerChannel,
-  DataObjectOwnerDao,
-  DataObjectOwnerCouncil,
-  DataObjectOwnerWorkingGroup,
-  LiaisonJudgement,
-  Worker,
-  WorkerType,
-} from 'query-node'
-
-export async function dataDirectory_ContentAdded(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { contentParameters, storageObjectOwner } = new DataDirectory.ContentAddedEvent(event).data
-
-  // save all content objects
-  for (const parameters of contentParameters) {
-    const owner = convertStorageObjectOwner(storageObjectOwner)
-    const dataObject = await prepareDataObject(db, parameters, event, owner)
-
-    // fill in auto-generated fields
-    dataObject.createdAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-    dataObject.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-    await db.save<DataObject>(dataObject)
-  }
-
-  // emit log event
-  logger.info('Storage content has beed added', {
-    ids: contentParameters.map((item) => encodeContentId(item.content_id)),
-  })
-}
-
-export async function dataDirectory_ContentRemoved(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { contentId: contentIds } = new DataDirectory.ContentRemovedEvent(event).data
-
-  // load assets
-  const dataObjects = await db.getMany(DataObject, {
-    where: {
-      joystreamContentId: In(contentIds.map((item) => encodeContentId(item))),
-    } as FindConditions<DataObject>,
-  })
-
-  // store dataObject ids before they are deleted (for logging purposes)
-  const dataObjectIds = dataObjects.map((item) => item.id)
-
-  // remove assets from database
-  for (const item of dataObjects) {
-    // ensure dataObject is nowhere used to prevent db constraint error
-    await disconnectDataObjectRelations(db, item)
-
-    // remove data object
-    await db.remove<DataObject>(item)
-  }
-
-  // emit log event
-  logger.info('Storage content have been removed', { id: contentIds, dataObjectIds })
-}
-
-export async function dataDirectory_ContentAccepted(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { contentId, storageProviderId } = new DataDirectory.ContentAcceptedEvent(event).data
-  const encodedContentId = encodeContentId(contentId)
-
-  // load asset
-  const dataObject = await db.get(DataObject, {
-    where: { joystreamContentId: encodedContentId } as FindConditions<DataObject>,
-  })
-
-  // ensure object exists
-  if (!dataObject) {
-    return inconsistentState('Non-existing content acceptation requested', encodedContentId)
-  }
-
-  // load storage provider
-  const worker = await db.get(Worker, {
-    where: {
-      workerId: storageProviderId.toString(),
-      type: WorkerType.STORAGE,
-    } as FindConditions<Worker>,
-  })
-
-  // ensure object exists
-  if (!worker) {
-    return inconsistentState('Missing Storage Provider Id', storageProviderId)
-  }
-
-  // update object
-  dataObject.liaison = worker
-  dataObject.liaisonJudgement = LiaisonJudgement.ACCEPTED
-
-  // set last update time
-  dataObject.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save object
-  await db.save<DataObject>(dataObject)
-
-  // emit log event
-  logger.info('Storage content has been accepted', { id: encodedContentId })
-
-  // update asset availability for all connected channels and videos
-  // this will not be needed after redudant AssetAvailability will be removed (after some Hydra upgrades)
-  await updateConnectedAssets(db, dataObject)
-}
-
-/// ///////////////// Updating connected entities ////////////////////////////////
-
-async function updateConnectedAssets(db: DatabaseManager, dataObject: DataObject) {
-  await updateSingleConnectedAsset(db, new Channel(), 'avatarPhoto', dataObject)
-  await updateSingleConnectedAsset(db, new Channel(), 'coverPhoto', dataObject)
-
-  await updateSingleConnectedAsset(db, new Video(), 'thumbnailPhoto', dataObject)
-  await updateSingleConnectedAsset(db, new Video(), 'media', dataObject)
-}
-
-// async function updateSingleConnectedAsset(db: DatabaseManager, type: typeof Channel | typeof Video, propertyName: string, dataObject: DataObject) {
-async function updateSingleConnectedAsset<T extends Channel | Video>(
-  db: DatabaseManager,
-  type: T,
-  propertyName: string,
-  dataObject: DataObject
-) {
-  // prepare lookup condition
-  const condition = {
-    where: {
-      [propertyName + 'DataObject']: dataObject,
-    },
-  } // as FindConditions<T>
-
-  // NOTE: we don't need to retrieve multiple channels/videos via `db.getMany()` because dataObject
-  //       is allowed to be associated only with one channel/video in runtime
-
-  // in therory the following condition(s) can be generalized `... db.get(type, ...` but in practice it doesn't work :-\
-  const item = type instanceof Channel ? await db.get(Channel, condition) : await db.get(Video, condition)
-
-  // escape when no dataObject association found
-  if (!item) {
-    return
-  }
-
-  item[propertyName + 'Availability'] = AssetAvailability.ACCEPTED
-
-  if (type instanceof Channel) {
-    await db.save<Channel>(item)
-
-    // emit log event
-    logger.info('Channel using Content has been accepted', {
-      channelId: item.id.toString(),
-      joystreamContentId: dataObject.joystreamContentId,
-    })
-  } else {
-    await db.save<Video>(item)
-
-    // emit log event
-    logger.info('Video using Content has been accepted', {
-      videoId: item.id.toString(),
-      joystreamContentId: dataObject.joystreamContentId,
-    })
-  }
-}
-
-// removes connection between dataObject and other entities
-async function disconnectDataObjectRelations(db: DatabaseManager, dataObject: DataObject) {
-  await disconnectSingleDataObjectRelation(db, new Channel(), 'avatarPhoto', dataObject)
-  await disconnectSingleDataObjectRelation(db, new Channel(), 'coverPhoto', dataObject)
-
-  await disconnectSingleDataObjectRelation(db, new Video(), 'thumbnailPhoto', dataObject)
-  await disconnectSingleDataObjectRelation(db, new Video(), 'media', dataObject)
-}
-
-async function disconnectSingleDataObjectRelation<T extends Channel | Video>(
-  db: DatabaseManager,
-  type: T,
-  propertyName: string,
-  dataObject: DataObject
-) {
-  // prepare lookup condition
-  const condition = {
-    where: {
-      [propertyName + 'DataObject']: dataObject,
-    },
-  } // as FindConditions<T>
-
-  // NOTE: we don't need to retrieve multiple channels/videos via `db.getMany()` because dataObject
-  //       is allowed to be associated only with one channel/video in runtime
-
-  // in therory the following condition(s) can be generalized `... db.get(type, ...` but in practice it doesn't work :-\
-  const item = type instanceof Channel ? await db.get(Channel, condition) : await db.get(Video, condition)
-
-  // escape when no dataObject association found
-  if (!item) {
-    return
-  }
-
-  item[propertyName + 'Availability'] = AssetAvailability.INVALID
-  item[propertyName + 'DataObject'] = null
-
-  if (type instanceof Channel) {
-    await db.save<Channel>(item)
-
-    // emit log event
-    logger.info('Content has been disconnected from Channel', {
-      channelId: item.id.toString(),
-      joystreamContentId: dataObject.joystreamContentId,
-    })
-  } else {
-    // type instanceof Video
-    await db.save<Video>(item)
-
-    // emit log event
-    logger.info('Content has been disconnected from Video', {
-      videoId: item.id.toString(),
-      joystreamContentId: dataObject.joystreamContentId,
-    })
-  }
-}
-
-/// ///////////////// Helpers ////////////////////////////////////////////////////
-
-function convertStorageObjectOwner(objectOwner: StorageObjectOwner): typeof DataObjectOwner {
-  if (objectOwner.isMember) {
-    const owner = new DataObjectOwnerMember()
-    owner.member = objectOwner.asMember.toNumber()
-
-    return owner
-  }
-
-  if (objectOwner.isChannel) {
-    const owner = new DataObjectOwnerChannel()
-    owner.channel = objectOwner.asChannel.toNumber()
-
-    return owner
-  }
-
-  if (objectOwner.isDao) {
-    const owner = new DataObjectOwnerDao()
-    owner.dao = objectOwner.asDao.toNumber()
-
-    return owner
-  }
-
-  if (objectOwner.isCouncil) {
-    return new DataObjectOwnerCouncil()
-  }
-
-  if (objectOwner.isWorkingGroup) {
-    const owner = new DataObjectOwnerWorkingGroup()
-    owner.workingGroup = objectOwner.asWorkingGroup.toNumber()
-
-    return owner
-  }
-
-  logger.error('Not implemented StorageObjectOwner type', { objectOwner: objectOwner.toString() })
-  throw new Error('Not implemented StorageObjectOwner type')
-}
-
-function encodeContentId(contentId: ContentId) {
-  const customContentId = new Custom_ContentId(registry, contentId)
-
-  return customContentId.encode()
-}

+ 0 - 237
query-node/mappings/sumer/workingGroup.ts

@@ -1,237 +0,0 @@
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { FindConditions } from 'typeorm'
-import { Bytes } from '@polkadot/types'
-import { fixBlockTimestamp } from './eventFix'
-
-import { convertBytesToString, inconsistentState, logger, getNextId } from './common'
-
-import { Channel, Worker, WorkerType } from 'query-node'
-import { GatewayWorkingGroup, StorageWorkingGroup } from '../../generated/types'
-import { ApplicationId, ApplicationIdToWorkerIdMap, WorkerId } from '@joystream/types/augment'
-
-/// ///////////////// Storage working group //////////////////////////////////////
-
-export async function storageWorkingGroup_OpeningFilled(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { applicationIdToWorkerIdMap } = new StorageWorkingGroup.OpeningFilledEvent(event).data
-
-  // call generic processing
-  await workingGroup_OpeningFilled(db, WorkerType.STORAGE, applicationIdToWorkerIdMap, event)
-}
-
-export async function storageWorkingGroup_WorkerStorageUpdated(
-  db: DatabaseManager,
-  event: SubstrateEvent
-): Promise<void> {
-  // read event data
-  const { workerId, bytes: newMetadata } = new StorageWorkingGroup.WorkerStorageUpdatedEvent(event).data
-
-  // call generic processing
-  await workingGroup_WorkerStorageUpdated(db, WorkerType.STORAGE, workerId, newMetadata)
-}
-
-export async function storageWorkingGroup_TerminatedWorker(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new StorageWorkingGroup.TerminatedWorkerEvent(event).data
-
-  // call generic processing
-  await workingGroup_TerminatedWorker(db, event, WorkerType.STORAGE, workerId)
-}
-
-export async function storageWorkingGroup_WorkerExited(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new StorageWorkingGroup.WorkerExitedEvent(event).data
-
-  // call generic processing
-  await workingGroup_WorkerExited(db, event, WorkerType.STORAGE, workerId)
-}
-
-export async function storageWorkingGroup_TerminatedLeader(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new StorageWorkingGroup.TerminatedLeaderEvent(event).data
-
-  // call generic processing
-  await workingGroup_TerminatedLeader(db, event, WorkerType.STORAGE, workerId)
-}
-
-/// ///////////////// Gateway working group //////////////////////////////////////
-
-export async function gatewayWorkingGroup_OpeningFilled(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { applicationIdToWorkerIdMap } = new GatewayWorkingGroup.OpeningFilledEvent(event).data
-
-  // call generic processing
-  await workingGroup_OpeningFilled(db, WorkerType.GATEWAY, applicationIdToWorkerIdMap, event)
-}
-
-export async function gatewayWorkingGroup_WorkerStorageUpdated(
-  db: DatabaseManager,
-  event: SubstrateEvent
-): Promise<void> {
-  // read event data
-  const { workerId, bytes: newMetadata } = new GatewayWorkingGroup.WorkerStorageUpdatedEvent(event).data
-
-  // call generic processing
-  await workingGroup_WorkerStorageUpdated(db, WorkerType.GATEWAY, workerId, newMetadata)
-}
-
-export async function gatewayWorkingGroup_TerminatedWorker(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new GatewayWorkingGroup.TerminatedWorkerEvent(event).data
-
-  // call generic processing
-  await workingGroup_TerminatedWorker(db, event, WorkerType.GATEWAY, workerId)
-}
-
-export async function gatewayWorkingGroup_WorkerExited(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new GatewayWorkingGroup.WorkerExitedEvent(event).data
-
-  // call generic processing
-  await workingGroup_WorkerExited(db, event, WorkerType.GATEWAY, workerId)
-}
-
-export async function gatewayWorkingGroup_TerminatedLeader(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
-  // read event data
-  const { workerId } = new GatewayWorkingGroup.TerminatedLeaderEvent(event).data
-
-  // call generic processing
-  await workingGroup_TerminatedLeader(db, event, WorkerType.GATEWAY, workerId)
-}
-
-/// ///////////////// Generic working group processing ///////////////////////////
-
-export async function workingGroup_OpeningFilled(
-  db: DatabaseManager,
-  workerType: WorkerType,
-  applicationIdToWorkerIdMap: ApplicationIdToWorkerIdMap,
-  event: SubstrateEvent
-): Promise<void> {
-  const workerIds = [...applicationIdToWorkerIdMap.values()]
-
-  for (const workerId of workerIds) {
-    await createWorker(db, workerId, workerType, event)
-  }
-
-  // emit log event
-  logger.info('Workers have been created', { ids: workerIds.map((item) => item.toString()), workerType })
-}
-
-export async function workingGroup_WorkerStorageUpdated(
-  db: DatabaseManager,
-  workerType: WorkerType,
-  workerId: WorkerId,
-  newMetadata: Bytes
-): Promise<void> {
-  // load worker
-  const worker = await db.get(Worker, {
-    where: {
-      workerId: workerId.toString(),
-      type: workerType,
-    } as FindConditions<Worker>,
-  })
-
-  // ensure worker exists
-  if (!worker) {
-    return inconsistentState('Non-existing worker update requested', workerId)
-  }
-
-  worker.metadata = convertBytesToString(newMetadata)
-
-  await db.save<Worker>(worker)
-
-  // emit log event
-  logger.info('Worker has been updated', { workerId, workerType })
-}
-
-export async function workingGroup_TerminatedWorker(
-  db: DatabaseManager,
-  event: SubstrateEvent,
-  workerType: WorkerType,
-  workerId: WorkerId
-): Promise<void> {
-  // do removal logic
-  await deactivateWorker(db, event, workerType, workerId)
-
-  // emit log event
-  logger.info('Worker has been removed (worker terminated)', { workerId, workerType })
-}
-
-export async function workingGroup_WorkerExited(
-  db: DatabaseManager,
-  event: SubstrateEvent,
-  workerType: WorkerType,
-  workerId: WorkerId
-): Promise<void> {
-  // do removal logic
-  await deactivateWorker(db, event, workerType, workerId)
-
-  // emit log event
-  logger.info('Worker has been removed (worker exited)', { workerId, workerType })
-}
-
-export async function workingGroup_TerminatedLeader(
-  db: DatabaseManager,
-  event: SubstrateEvent,
-  workerType: WorkerType,
-  workerId: WorkerId
-): Promise<void> {
-  // do removal logic
-  await deactivateWorker(db, event, workerType, workerId)
-
-  // emit log event
-  logger.info('Working group leader has been removed (worker exited)', { workerId, workerType })
-}
-
-/// ///////////////// Helpers ////////////////////////////////////////////////////
-
-async function createWorker(
-  db: DatabaseManager,
-  workerId: WorkerId,
-  workerType: WorkerType,
-  event: SubstrateEvent
-): Promise<void> {
-  // create entity
-  const newWorker = new Worker({
-    id: await getNextId(db),
-    workerId: workerId.toString(),
-    type: workerType,
-    isActive: true,
-
-    createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-    updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
-  })
-
-  // save worker
-  await db.save<Worker>(newWorker)
-}
-
-async function deactivateWorker(
-  db: DatabaseManager,
-  event: SubstrateEvent,
-  workerType: WorkerType,
-  workerId: WorkerId
-) {
-  // load worker
-  const worker = await db.get(Worker, {
-    where: {
-      workerId: workerId.toString(),
-      type: workerType,
-    } as FindConditions<Worker>,
-  })
-
-  // ensure worker exists
-  if (!worker) {
-    return inconsistentState('Non-existing worker deletion requested', workerId)
-  }
-
-  // update worker
-  worker.isActive = false
-
-  // set last update time
-  worker.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
-
-  // save worker
-  await db.save<Worker>(worker)
-}

+ 1 - 1
query-node/mappings/tsconfig.json

@@ -18,5 +18,5 @@
       "@polkadot/types/augment": ["../../types/augment/augment-types.ts"]
     }
   },
-  "include": ["./giza/**/*"]
+  "include": ["./**/*"]
 }

+ 153 - 0
query-node/mappings/workingGroup.ts

@@ -0,0 +1,153 @@
+import { EventContext, StoreContext, DatabaseManager, SubstrateEvent } from '@joystream/hydra-common'
+import { bytesToString, inconsistentState, logger } from './common'
+import { Worker, WorkerType } from 'query-node/dist/model'
+import { StorageWorkingGroup } from './generated/types'
+import { WorkerId } from '@joystream/types/augment'
+
+export async function workingGroup_OpeningFilled({ event, store }: EventContext & StoreContext): Promise<void> {
+  const workerType = getWorkerType(event)
+  if (!workerType) {
+    return
+  }
+
+  const [, applicationIdToWorkerIdMap] = new StorageWorkingGroup.OpeningFilledEvent(event).params
+  const workerIds = [...applicationIdToWorkerIdMap.values()]
+
+  for (const workerId of workerIds) {
+    await createWorker(store, workerId, workerType, event)
+  }
+
+  // emit log event
+  logger.info('Workers have been created', { ids: workerIds.map((item) => item.toString()), workerType })
+}
+
+export async function workingGroup_WorkerStorageUpdated({ event, store }: EventContext & StoreContext): Promise<void> {
+  const workerType = getWorkerType(event)
+  if (!workerType) {
+    return
+  }
+  const [workerId, newMetadata] = new StorageWorkingGroup.WorkerStorageUpdatedEvent(event).params
+
+  // load worker
+  const worker = await store.get(Worker, {
+    where: {
+      workerId: workerId.toString(),
+      type: workerType,
+    },
+  })
+
+  // ensure worker exists
+  if (!worker) {
+    return inconsistentState('Non-existing worker update requested', workerId)
+  }
+
+  worker.metadata = bytesToString(newMetadata)
+
+  await store.save<Worker>(worker)
+
+  // emit log event
+  logger.info('Worker has been updated', { workerId, workerType })
+}
+
+export async function workingGroup_TerminatedWorker({ event, store }: EventContext & StoreContext): Promise<void> {
+  const workerType = getWorkerType(event)
+  if (!workerType) {
+    return
+  }
+  const [workerId] = new StorageWorkingGroup.TerminatedWorkerEvent(event).params
+
+  // do removal logic
+  await deactivateWorker(store, event, workerType, workerId)
+
+  // emit log event
+  logger.info('Worker has been removed (worker terminated)', { workerId, workerType })
+}
+
+export async function workingGroup_WorkerExited({ event, store }: EventContext & StoreContext): Promise<void> {
+  const workerType = getWorkerType(event)
+  if (!workerType) {
+    return
+  }
+  const [workerId] = new StorageWorkingGroup.WorkerExitedEvent(event).params
+
+  // do removal logic
+  await deactivateWorker(store, event, workerType, workerId)
+
+  // emit log event
+  logger.info('Worker has been removed (worker exited)', { workerId, workerType })
+}
+
+export async function workingGroup_TerminatedLeader({ event, store }: EventContext & StoreContext): Promise<void> {
+  const workerType = getWorkerType(event)
+  if (!workerType) {
+    return
+  }
+  const [workerId] = new StorageWorkingGroup.WorkerExitedEvent(event).params
+
+  // do removal logic
+  await deactivateWorker(store, event, workerType, workerId)
+
+  // emit log event
+  logger.info('Working group leader has been removed (worker exited)', { workerId, workerType })
+}
+
+/// ///////////////// Helpers ////////////////////////////////////////////////////
+
+function getWorkerType(event: SubstrateEvent): WorkerType | null {
+  if (event.section === 'storageWorkingGroup') {
+    return WorkerType.STORAGE
+  } else if (event.section === 'gatewayWorkingGroup') {
+    return WorkerType.GATEWAY
+  }
+  return null
+}
+
+async function createWorker(
+  db: DatabaseManager,
+  workerId: WorkerId,
+  workerType: WorkerType,
+  event: SubstrateEvent
+): Promise<void> {
+  // create entity
+  const newWorker = new Worker({
+    id: `${workerType}-${workerId.toString()}`,
+    workerId: workerId.toString(),
+    type: workerType,
+    isActive: true,
+
+    createdAt: new Date(event.blockTimestamp),
+    updatedAt: new Date(event.blockTimestamp),
+  })
+
+  // save worker
+  await db.save<Worker>(newWorker)
+}
+
+async function deactivateWorker(
+  db: DatabaseManager,
+  event: SubstrateEvent,
+  workerType: WorkerType,
+  workerId: WorkerId
+) {
+  // load worker
+  const worker = await db.get(Worker, {
+    where: {
+      workerId: workerId.toString(),
+      type: workerType,
+    },
+  })
+
+  // ensure worker exists
+  if (!worker) {
+    return inconsistentState('Non-existing worker deletion requested', workerId)
+  }
+
+  // update worker
+  worker.isActive = false
+
+  // set last update time
+  worker.updatedAt = new Date(event.blockTimestamp)
+
+  // save worker
+  await db.save<Worker>(worker)
+}

+ 28 - 182
query-node/schemas/content.graphql

@@ -1,115 +1,33 @@
-"Category of media channel"
-type ChannelCategory @entity {
-  id: ID!
-
-  "The name of the category"
-  name: String @fulltext(query: "channelCategoriesByName")
-
-  channels: [Channel!]! @derivedFrom(field: "category")
-
-  createdInBlock: Int!
+type AssetExternal @variant {
+  # FIXME: [String!] currnetly not supported in variants
+  "JSON array of the urls"
+  urls: String!
 }
 
-"Asset availability representation"
-enum AssetAvailability {
-  "Asset is available in storage"
-  ACCEPTED,
-
-  "Asset is being uploaded to storage"
-  PENDING,
-
-  "Invalid storage (meta)data used"
-  INVALID,
+type AssetJoystreamStorage @variant {
+  "Related data object"
+  dataObject: StorageDataObject!
 }
 
-"The decision of the storage provider when it acts as liaison"
-enum LiaisonJudgement {
-  "Content awaits for a judgment"
-  PENDING,
-
-  "Content accepted"
-  ACCEPTED,
+# FIXME: https://github.com/Joystream/hydra/issues/434
+type AssetNone @variant {
+  _phantom: Int
 }
 
-"Manages content ids, type and storage provider decision about it"
-type DataObject @entity {
-  "Content owner"
-  owner: DataObjectOwner!
-
-  "Content added at"
-  createdInBlock: Int!
-
-  "Content type id"
-  typeId: Int!
-
-  "Content size in bytes"
-  size: Int!
-
-  "Storage provider id of the liaison"
-  liaison: Worker # liaison is unset until storage provider accepts or rejects the content
+union Asset = AssetExternal | AssetJoystreamStorage | AssetNone
 
-  "Storage provider as liaison judgment"
-  liaisonJudgement: LiaisonJudgement!
-
-  "IPFS content id"
-  ipfsContentId: String!
-
-  "Joystream runtime content"
-  joystreamContentId: String!
-}
-
-"Owner type for storage object"
-union DataObjectOwner = DataObjectOwnerMember
-  | DataObjectOwnerChannel
-  | DataObjectOwnerDao
-  | DataObjectOwnerCouncil
-  | DataObjectOwnerWorkingGroup
-
-"Asset owned by a member"
-type DataObjectOwnerMember @variant {
-  # use `Int` instead of `Membership` before variant relations are featured in Hydra
-  # TODO: setup proper relations
-  #"Member identifier"
-  #memberId: Membership!
-  "Member identifier"
-  member: Int!
-
-  "Variant needs to have at least one property. This value is not used."
-  dummy: Int
-}
-
-"Asset owned by a channel"
-type DataObjectOwnerChannel @variant {
-  # use `Int` instead of `Channel` before variant relations are featured in Hydra
-  #"Channel identifier"
-  #channel: Channel!
-  "Channel identifier"
-  channel: Int!
-
-  "Variant needs to have at least one property. This value is not used."
-  dummy: Int
-}
+"Category of media channel"
+type ChannelCategory @entity {
+  id: ID!
 
-"Asset owned by a DAO"
-type DataObjectOwnerDao @variant {
-  "DAO identifier"
-  dao: Int!
-}
+  "The name of the category"
+  name: String @fulltext(query: "channelCategoriesByName")
 
-"Asset owned by the Council"
-type DataObjectOwnerCouncil @variant {
-  "Variant needs to have at least one property. This value is not used."
-  dummy: Int
-}
+  channels: [Channel!]! @derivedFrom(field: "category")
 
-"Asset owned by a WorkingGroup"
-type DataObjectOwnerWorkingGroup @variant {
-  "Working group identifier"
-  workingGroup: Int!
+  createdInBlock: Int!
 }
 
-#### High Level Derivative Entities ####
-
 type Language @entity {
   "Runtime entity identifier (EntityId)"
   id: ID!
@@ -141,31 +59,11 @@ type Channel @entity {
   "The description of a Channel"
   description: String
 
-  ### Cover photo asset ###
-
-  # Channel's cover (background) photo. Recommended ratio: 16:9.
-
-  "Asset's data object"
-  coverPhotoDataObject: DataObject
-
-  "URLs where the asset content can be accessed (if any)"
-  coverPhotoUrls: [String!]
-
-  "Availability meta information"
-  coverPhotoAvailability: AssetAvailability!
-
-  ### Avatar photo asset ###
-
-  # Channel's avatar photo.
-
-  "Asset's data object"
-  avatarPhotoDataObject: DataObject
-
-  "URLs where the asset content can be accessed (if any)"
-  avatarPhotoUrls: [String!]
+  "Channel's cover (background) photo asset. Recommended ratio: 16:9."
+  coverPhoto: Asset
 
-  "Availability meta information"
-  avatarPhotoAvailability: AssetAvailability!
+  "Channel's avatar photo asset."
+  avatarPhoto: Asset
 
   ##########################
 
@@ -213,7 +111,7 @@ type Video @entity {
   id: ID!
 
   "Reference to member's channel"
-  channel: Channel
+  channel: Channel!
 
   "Reference to a video category"
   category: VideoCategory
@@ -227,18 +125,8 @@ type Video @entity {
   "Video duration in seconds"
   duration: Int
 
-  ### Thumbnail asset ###
-
-  # Video thumbnail (recommended ratio: 16:9)
-
-  "Asset's data object"
-  thumbnailPhotoDataObject: DataObject
-
-  "URLs where the asset content can be accessed (if any)"
-  thumbnailPhotoUrls: [String!]
-
-  "Availability meta information"
-  thumbnailPhotoAvailability: AssetAvailability!
+  "Video thumbnail asset (recommended ratio: 16:9)"
+  thumbnailPhoto: Asset
 
   ##########################
 
@@ -263,18 +151,8 @@ type Video @entity {
   "License under the video is published"
   license: License
 
-  ### Media asset ###
-
-  # Reference to video asset
-
-  "Asset's data object"
-  mediaDataObject: DataObject
-
-  "URLs where the asset content can be accessed (if any)"
-  mediaUrls: [String!]
-
-  "Availability meta information"
-  mediaAvailability: AssetAvailability!
+  "Video media asset"
+  media: Asset
 
   ##########################
 
@@ -301,7 +179,7 @@ type VideoMediaMetadata @entity {
   pixelHeight: Int
 
   "Video media size in bytes"
-  size: Int
+  size: BigInt
 
   video: Video @derivedFrom(field: "mediaMetadata")
 
@@ -332,35 +210,3 @@ type License @entity {
   "Custom license content"
   custom_text: String
 }
-
-enum WorkerType {
-  GATEWAY
-  STORAGE
-}
-
-type Worker @entity {
-  "Unique identifier"
-  id: ID!
-
-  "Sign of worker still being active"
-  isActive: Boolean!
-
-  "Runtime identifier"
-  workerId: String!
-
-  "Associated working group"
-  type: WorkerType!
-
-  "Custom metadata set by provider"
-  metadata: String
-
-  dataObjects: [DataObject!]! @derivedFrom(field: "liaison")
-}
-
-type NextEntityId @entity {
-  "Unique identifier"
-  id: ID!
-
-  "Next deterministic id for entities without custom id"
-  nextId: Int!
-}

+ 21 - 20
query-node/schemas/storage.graphql

@@ -3,12 +3,23 @@ type StorageSystemParameters @entity {
   "Blacklisted content hashes"
   blacklist: [String!]
 
-  # TODO: Consider if parameters like:
-  # dataObjectFeePerMB,
-  # storageBucketBagsLimit,
-  # storageBucketsVoucherMaxLimits,
-  # etc.
-  # are needed here (they can be easily queried from the node)
+  "How many buckets can be assigned to store a bag"
+  storageBucketsPerBagLimit: Int!
+
+  "How many buckets can be assigned to distribute a bag"
+  distributionBucketsPerBagLimit: Int!
+
+  "Whether the uploading is globally blocked"
+  uploadingBlocked: Boolean!
+
+  "Additional fee for storing 1 MB of data"
+  dataObjectFeePerMB: BigInt!
+
+  "Global max. number of objects a storage bucket can store (can also be further limitted the provider)"
+  storageBucketMaxObjectsCountLimit: BigInt!
+
+  "Global max. size of objects a storage bucket can store (can also be further limitted the provider)"
+  storageBucketMaxObjectsSizeLimit: BigInt!
 }
 
 type StorageBucketOperatorStatusMissing @variant {
@@ -77,12 +88,11 @@ type StorageBucket @entity {
   "Bucket's data object count limit"
   dataObjectCountLimit: BigInt!
 
-  # TODO: Are those useful for storage node?
-  # "Currently stored (assigned) data objects size"
-  # storedObjectsSize: BigInt!
+  "Number of assigned data objects"
+  dataObjectsCount: BigInt!
 
-  # "Currently stored (assigned) objects count"
-  # storedObjectsCount: BigInt!
+  "Total size of assigned data objects"
+  dataObjectsSize: BigInt!
 }
 
 type StorageBagOwnerCouncil @variant {
@@ -154,23 +164,14 @@ type StorageDataObject @entity {
   "Whether the data object was uploaded and accepted by the storage provider"
   isAccepted: Boolean!
 
-  # TODO: Is this useful for storage node?
-  # "A reward for the data object deletion"
-  # deletionPrize: BigInt!
-
   "Data object size in bytes"
   size: BigInt!
 
   "Storage bag the data object is part of"
   storageBag: StorageBag!
 
-  # TODO: Use "Bytes" for better optimalization?
   "IPFS content hash"
   ipfsHash: String!
-
-  # TODO: Use "Bytes" for better optimalization?
-  "Public key used to authenticate the uploader by the storage provider"
-  authenticationKey: String
 }
 
 type DistributionBucketFamilyMetadata @entity {

+ 17 - 0
query-node/schemas/workingGroups.graphql

@@ -0,0 +1,17 @@
+enum WorkerType {
+  GATEWAY
+  STORAGE
+}
+
+type Worker @entity {
+  "Unique identifier"
+  id: ID!
+  "Sign of worker still being active"
+  isActive: Boolean!
+  "Runtime identifier"
+  workerId: String!
+  "Associated working group"
+  type: WorkerType!
+  "Custom metadata set by provider"
+  metadata: String
+}

+ 22 - 3
runtime-modules/storage/src/lib.rs

@@ -319,6 +319,9 @@ pub trait Trait: frame_system::Trait + balances::Trait + membership::Trait {
     /// Max number of pending invitations per distribution bucket.
     type MaxNumberOfPendingInvitationsPerDistributionBucket: Get<u64>;
 
+    /// Max data object size in bytes.
+    type MaxDataObjectSize: Get<u64>;
+
     /// Demand the storage working group leader authorization.
     /// TODO: Refactor after merging with the Olympia release.
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult;
@@ -467,6 +470,9 @@ pub struct DataObject<Balance> {
 
     /// Object size in bytes.
     pub size: u64,
+
+    /// Content identifier presented as IPFS hash.
+    pub ipfs_content_id: Vec<u8>,
 }
 
 /// Type alias for the BagRecord.
@@ -652,9 +658,6 @@ pub type UploadParameters<T> = UploadParametersRecord<
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
 pub struct UploadParametersRecord<MemberId, ChannelId, AccountId, Balance> {
-    /// Public key used authentication in upload to liaison.
-    pub authentication_key: Vec<u8>,
-
     /// Static or dynamic bag to upload data.
     pub bag_id: BagIdType<MemberId, ChannelId>,
 
@@ -1427,6 +1430,9 @@ decl_error! {
 
         /// Distribution family bound to a bag creation policy.
         DistributionFamilyBoundToBagCreationPolicy,
+
+        /// Max data object size exceeded.
+        MaxDataObjectSizeExceeded,
     }
 }
 
@@ -1477,6 +1483,9 @@ decl_module! {
         const MaxNumberOfPendingInvitationsPerDistributionBucket: u64 =
             T::MaxNumberOfPendingInvitationsPerDistributionBucket::get();
 
+        /// Exports const - max data object size in bytes.
+        const MaxDataObjectSize: u64 = T::MaxDataObjectSize::get();
+
         // ===== Storage Lead actions =====
 
         /// Delete storage bucket. Must be empty. Storage operator must be missing.
@@ -2900,6 +2909,7 @@ impl<T: Trait> Module<T> {
             accepted: false,
             deletion_prize,
             size: obj.size,
+            ipfs_content_id: obj.ipfs_content_id,
         });
 
         let mut next_data_object_id = Self::next_data_object_id();
@@ -3184,6 +3194,15 @@ impl<T: Trait> Module<T> {
             Error::<T>::NoObjectsOnUpload
         );
 
+        // Check data objects' max size.
+        ensure!(
+            params
+                .object_creation_list
+                .iter()
+                .all(|obj| obj.size <= T::MaxDataObjectSize::get()),
+            Error::<T>::MaxDataObjectSizeExceeded
+        );
+
         let bag = Self::ensure_bag_exists(&params.bag_id)?;
 
         let new_objects_number: u64 = params.object_creation_list.len().saturated_into();

+ 2 - 0
runtime-modules/storage/src/tests/mocks.rs

@@ -65,6 +65,7 @@ parameter_types! {
     pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4;
     pub const DistributionBucketsPerBagValueConstraint: crate::DistributionBucketsPerBagValueConstraint =
         crate::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
+    pub const MaxDataObjectSize: u64 = 400;
 }
 
 pub const STORAGE_WG_LEADER_ACCOUNT_ID: u64 = 100001;
@@ -101,6 +102,7 @@ impl crate::Trait for Test {
     type DistributionBucketsPerBagValueConstraint = DistributionBucketsPerBagValueConstraint;
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
         MaxNumberOfPendingInvitationsPerDistributionBucket;
+    type MaxDataObjectSize = MaxDataObjectSize;
 
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
         let account_id = ensure_signed(origin)?;

+ 29 - 33
runtime-modules/storage/src/tests/mod.rs

@@ -24,7 +24,7 @@ use crate::{
 use mocks::{
     build_test_externalities, Balances, DataObjectDeletionPrize,
     DefaultChannelDynamicBagNumberOfStorageBuckets, DefaultMemberDynamicBagNumberOfStorageBuckets,
-    InitialStorageBucketsNumberForDynamicBag, MaxDistributionBucketFamilyNumber,
+    InitialStorageBucketsNumberForDynamicBag, MaxDataObjectSize, MaxDistributionBucketFamilyNumber,
     MaxDistributionBucketNumberPerFamily, MaxNumberOfDataObjectsPerBag, MaxRandomIterationNumber,
     Storage, Test, ANOTHER_DISTRIBUTION_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID,
     DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID, DEFAULT_DISTRIBUTION_PROVIDER_ID,
@@ -360,7 +360,6 @@ fn update_storage_buckets_for_bags_succeeded_with_voucher_usage() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -424,7 +423,6 @@ fn update_storage_buckets_for_bags_fails_with_exceeding_the_voucher_objects_numb
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -470,7 +468,6 @@ fn update_storage_buckets_for_bags_fails_with_exceeding_the_voucher_objects_tota
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -671,7 +668,6 @@ fn upload_succeeded() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -695,6 +691,9 @@ fn upload_succeeded() {
             Storage::data_object_by_id(&bag_id, &data_object_id),
             DataObject {
                 size: upload_params.object_creation_list[0].size,
+                ipfs_content_id: upload_params.object_creation_list[0]
+                    .ipfs_content_id
+                    .clone(),
                 deletion_prize: DataObjectDeletionPrize::get(),
                 accepted: false,
             }
@@ -717,6 +716,28 @@ fn upload_succeeded() {
     });
 }
 
+#[test]
+fn upload_failed_with_exceeding_the_data_object_max_size() {
+    build_test_externalities().execute_with(|| {
+        let initial_balance = 1000;
+        increase_account_balance(&DEFAULT_MEMBER_ACCOUNT_ID, initial_balance);
+
+        let mut data_object_list = create_single_data_object();
+        data_object_list[0].size = MaxDataObjectSize::get() + 1;
+
+        let upload_params = UploadParameters::<Test> {
+            bag_id: BagId::<Test>::Static(StaticBagId::Council),
+            deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
+            object_creation_list: data_object_list,
+            expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
+        };
+
+        UploadFixture::default()
+            .with_params(upload_params.clone())
+            .call_and_assert(Err(Error::<Test>::MaxDataObjectSizeExceeded.into()));
+    });
+}
+
 #[test]
 fn upload_succeeded_with_data_size_fee() {
     build_test_externalities().execute_with(|| {
@@ -732,7 +753,6 @@ fn upload_succeeded_with_data_size_fee() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -768,7 +788,6 @@ fn upload_succeeded_with_active_storage_bucket_having_voucher() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id,
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -803,7 +822,6 @@ fn upload_fails_with_active_storage_bucket_with_voucher_object_number_limit_exce
 
         let upload_params = UploadParameters::<Test> {
             bag_id,
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -838,7 +856,6 @@ fn upload_fails_with_active_storage_bucket_with_voucher_object_size_limit_exceed
 
         let upload_params = UploadParameters::<Test> {
             bag_id,
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -864,7 +881,6 @@ fn upload_succeeded_with_dynamic_bag() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Dynamic(dynamic_bag_id.clone()),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -888,6 +904,9 @@ fn upload_succeeded_with_dynamic_bag() {
             Storage::data_object_by_id(&bag_id, &data_object_id),
             DataObject {
                 size: upload_params.object_creation_list[0].size,
+                ipfs_content_id: upload_params.object_creation_list[0]
+                    .ipfs_content_id
+                    .clone(),
                 deletion_prize: DataObjectDeletionPrize::get(),
                 accepted: false,
             }
@@ -902,7 +921,6 @@ fn upload_fails_with_non_existent_dynamic_bag() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Dynamic(dynamic_bag_id.clone()),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -921,7 +939,6 @@ fn upload_succeeded_with_non_empty_bag() {
 
         let upload_params1 = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_data_object_candidates(1, 2),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -933,7 +950,6 @@ fn upload_succeeded_with_non_empty_bag() {
 
         let upload_params2 = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_data_object_candidates(3, 2),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -964,7 +980,6 @@ fn upload_fails_with_zero_object_size() {
     build_test_externalities().execute_with(|| {
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: vec![DataObjectCreationParameters {
                 ipfs_content_id: vec![1],
@@ -984,7 +999,6 @@ fn upload_fails_with_empty_object_cid() {
     build_test_externalities().execute_with(|| {
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: vec![DataObjectCreationParameters {
                 ipfs_content_id: Vec::new(),
@@ -1007,7 +1021,6 @@ fn upload_fails_with_max_data_object_size_exceeded() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_data_object_candidates(1, invalid_object_number),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1024,7 +1037,6 @@ fn upload_fails_with_insufficient_balance_for_deletion_prize() {
     build_test_externalities().execute_with(|| {
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1043,7 +1055,6 @@ fn upload_fails_with_insufficient_balance_for_data_size_fee() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1078,7 +1089,6 @@ fn upload_fails_with_data_size_fee_changed() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1105,7 +1115,6 @@ fn upload_failed_with_blocked_uploading() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1140,7 +1149,6 @@ fn upload_failed_with_blacklisted_data_object() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: BagId::<Test>::Static(StaticBagId::Council),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list,
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1283,7 +1291,6 @@ fn accept_pending_data_objects_succeeded() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1348,7 +1355,6 @@ fn accept_pending_data_objects_fails_with_unrelated_storage_bucket() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1443,7 +1449,6 @@ fn accept_pending_data_objects_succeeded_with_dynamic_bag() {
         let bag_id = BagId::<Test>::Dynamic(dynamic_bag_id.clone());
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1773,7 +1778,6 @@ fn move_data_objects_succeeded() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: src_bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1873,7 +1877,6 @@ fn move_data_objects_succeeded_having_voucher() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: src_bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -1948,7 +1951,6 @@ fn move_data_objects_fails_with_exceeding_voucher_object_number_limit() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: src_bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2007,7 +2009,6 @@ fn move_data_objects_fails_with_exceeding_voucher_objects_size_limit() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: src_bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2086,7 +2087,6 @@ fn delete_data_objects_succeeded() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2186,7 +2186,6 @@ fn delete_data_objects_fails_with_invalid_treasury_balance() {
         let council_bag_id = BagId::<Test>::Static(StaticBagId::Council);
         let upload_params = UploadParameters::<Test> {
             bag_id: council_bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: create_single_data_object(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2231,7 +2230,6 @@ fn delete_data_objects_succeeded_with_voucher_usage() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2657,7 +2655,6 @@ fn delete_storage_bucket_fails_with_non_empty_bucket() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),
@@ -2844,7 +2841,6 @@ fn storage_bucket_voucher_changed_event_fired() {
 
         let upload_params = UploadParameters::<Test> {
             bag_id: bag_id.clone(),
-            authentication_key: Vec::new(),
             deletion_prize_source_account_id: DEFAULT_MEMBER_ACCOUNT_ID,
             object_creation_list: object_creation_list.clone(),
             expected_data_size_fee: Storage::data_object_per_mega_byte_fee(),

+ 2 - 0
runtime/src/lib.rs

@@ -694,6 +694,7 @@ parameter_types! {
     pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4; //TODO: adjust value
     pub const DistributionBucketsPerBagValueConstraint: storage::DistributionBucketsPerBagValueConstraint =
         storage::DistributionBucketsPerBagValueConstraint {min: 3, max_min_diff: 7}; //TODO: adjust value
+    pub const MaxDataObjectSize: u64 = 10 * 1024 * 1024 * 1024; // 10 GB
 }
 
 impl storage::Trait for Runtime {
@@ -721,6 +722,7 @@ impl storage::Trait for Runtime {
     type DistributionBucketOperatorId = DistributionBucketOperatorId;
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
         MaxNumberOfPendingInvitationsPerDistributionBucket;
+    type MaxDataObjectSize = MaxDataObjectSize;
 
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
         StorageWorkingGroup::ensure_origin_is_active_leader(origin)

+ 1 - 1
storage-node-v2/package.json

@@ -1,6 +1,6 @@
 {
   "name": "storage-node-v2",
-  "description": "Jostream storage subsystem.",
+  "description": "Joystream storage subsystem.",
   "version": "0.1.0",
   "author": "Joystream contributors",
   "bin": {

+ 6 - 0
storage-node-v2/src/api-spec/openapi.yaml

@@ -174,6 +174,12 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/ErrorResponse'
+        401:
+          description: Unauthorized
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponse'
 
 components:
   securitySchemes:

+ 4 - 1
storage-node-v2/src/commands/server.ts

@@ -45,7 +45,10 @@ export default class Server extends ApiCommandBase {
     try {
       const port = flags.port
       const workerId = flags.worker ?? 0
-      const app = await createApp(api, account, workerId, flags.uploads)
+      const maxFileSize = await api.consts.storage.maxDataObjectSize.toNumber()
+      logger.debug(`Max file size runtime parameter: ${maxFileSize}`)
+
+      const app = await createApp(api, account, workerId, flags.uploads, maxFileSize)
       logger.info(`Listening on http://localhost:${port}`)
       app.listen(port)
     } catch (err) {

+ 22 - 6
storage-node-v2/src/services/webApi/app.ts

@@ -17,13 +17,15 @@ import { httpLogger, errorLogger } from '../../services/logger'
  * @param account - KeyringPair instance
  * @param workerId - storage provider ID (worker ID)
  * @param uploadsDir - directory for the file uploading
+ * @param maxFileSize - max allowed file size
  * @returns Express promise.
  */
 export async function createApp(
   api: ApiPromise,
   account: KeyringPair,
   workerId: number,
-  uploadsDir: string
+  uploadsDir: string,
+  maxFileSize: number
 ): Promise<Express> {
   const spec = path.join(__dirname, './../../api-spec/openapi.yaml')
 
@@ -52,7 +54,16 @@ export async function createApp(
         basePath: path.join(__dirname, './controllers'),
         resolver: OpenApiValidator.resolvers.modulePathResolver,
       },
-      fileUploader: { dest: uploadsDir },
+      fileUploader: {
+        dest: uploadsDir,
+        // Busboy library settings
+        limits: {
+          // For multipart forms, the max number of file fields (Default: Infinity)
+          files: 1,
+          // For multipart forms, the max file size (in bytes) (Default: Infinity)
+          fileSize: maxFileSize,
+        },
+      },
       validateSecurity: {
         handlers: {
           UploadAuth: validateUpload(api, account),
@@ -65,12 +76,17 @@ export async function createApp(
 
   /* eslint-disable @typescript-eslint/no-unused-vars */
   app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
-    // Request validation error handler.
+    // Express error handling recommendation:
+    // https://expressjs.com/en/guide/error-handling.html
+    if (res.headersSent) {
+      return next(err)
+    }
+
+    // Request error handler.
     if (err instanceof HttpError) {
-      res.status(err.status).json({
-        type: 'request_validation',
+      res.status(err.status || 500).json({
+        type: 'request_exception',
         message: err.message,
-        errors: err.errors,
       })
     } else {
       res.status(500).json({

+ 47 - 13
storage-node-v2/src/services/webApi/controllers/publicApi.ts

@@ -11,6 +11,7 @@ import { hashFile } from '../../../services/helpers/hashing'
 import { createNonce, getTokenExpirationTime } from '../../../services/helpers/tokenNonceKeeper'
 import { getFileInfo } from '../../../services/helpers/fileInfo'
 import { parseBagId } from '../../helpers/bagTypes'
+import { BagId } from '@joystream/types/storage'
 import logger from '../../../services/logger'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { ApiPromise } from '@polkadot/api'
@@ -19,6 +20,7 @@ import fs from 'fs'
 import path from 'path'
 import send from 'send'
 import { CLIError } from '@oclif/errors'
+import { hexToString } from '@polkadot/util'
 const fsPromises = fs.promises
 
 /**
@@ -107,10 +109,13 @@ export async function uploadFile(req: express.Request, res: express.Response): P
     const fileObj = getFileObject(req)
     cleanupFileName = fileObj.path
 
-    verifyFileSize(fileObj.size)
+    const api = getApi(res)
     await verifyFileMimeType(fileObj.path)
 
     const hash = await hashFile(fileObj.path)
+    const bagId = parseBagId(api, uploadRequest.bagId)
+
+    const accepted = await verifyDataObjectInfo(api, bagId, uploadRequest.dataObjectId, fileObj.size, hash)
 
     // Prepare new file name
     const newPath = fileObj.path.replace(fileObj.filename, hash)
@@ -119,11 +124,16 @@ export async function uploadFile(req: express.Request, res: express.Response): P
     await fsPromises.rename(fileObj.path, newPath)
     cleanupFileName = newPath
 
-    const api = getApi(res)
-    const bagId = parseBagId(api, uploadRequest.bagId)
-    await acceptPendingDataObjects(api, bagId, getAccount(res), getWorkerId(res), uploadRequest.storageBucketId, [
-      uploadRequest.dataObjectId,
-    ])
+    const workerId = getWorkerId(res)
+    if (!accepted) {
+      await acceptPendingDataObjects(api, bagId, getAccount(res), workerId, uploadRequest.storageBucketId, [
+        uploadRequest.dataObjectId,
+      ])
+    } else {
+      logger.warn(
+        `Received already accepted data object. DataObjectId = ${uploadRequest.dataObjectId} WorkerId = ${workerId}`
+      )
+    }
     res.status(201).json({
       id: hash,
     })
@@ -294,17 +304,41 @@ async function validateTokenRequest(api: ApiPromise, tokenRequest: UploadTokenRe
 }
 
 /**
- * Validates file size. It throws an error when file size exceeds the limit
+ * Validates the runtime info for the data object. It verifies contentID,
+ * file size, and 'accepted' status.
  *
- * @param fileSize - runtime API promise
- * @returns void promise.
+ * @param api - runtime API promise
+ * @param bagId - bag ID
+ * @param dataObjectId - data object ID to validate in runtime
+ * @param fileSize - file size to validate
+ * @param hash - file multihash
+ * @returns promise with the 'data object accepted' flag.
  */
-function verifyFileSize(fileSize: number) {
-  const MAX_FILE_SIZE = 1000000 // TODO: Get this const from the runtime
+async function verifyDataObjectInfo(
+  api: ApiPromise,
+  bagId: BagId,
+  dataObjectId: number,
+  fileSize: number,
+  hash: string
+): Promise<boolean> {
+  const dataObject = await api.query.storage.dataObjectsById(bagId, dataObjectId)
+
+  // Cannot get 'size' as a regular property.
+  const dataObjectSize = dataObject.getField('size')
+
+  if (dataObjectSize?.toNumber() !== fileSize) {
+    throw new WebApiError(`File size doesn't match the data object's size for data object ID = ${dataObjectId}`, 400)
+  }
 
-  if (fileSize > MAX_FILE_SIZE) {
-    throw new WebApiError('Max file size exceeded.', 400)
+  const runtimeHash = hexToString(dataObject.ipfsContentId.toString())
+  if (runtimeHash !== hash) {
+    throw new WebApiError(
+      `File multihash doesn't match the data object's ipfsContentId for data object ID = ${dataObjectId}`,
+      400
+    )
   }
+
+  return dataObject.accepted.valueOf()
 }
 
 /**

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů