<commit_before>/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import arrayFind from "array-find";
import { ICustomError } from "../errors";
import MediaError from "../errors/MediaError";
import log from "../log";
import arrayIncludes from "../utils/array-includes";
import Adaptation, {
  IAdaptationArguments,
  IAdaptationType,
  IRepresentationFilter,
  SUPPORTED_ADAPTATIONS_TYPE,
} from "./adaptation";

// Structure listing every `Adaptation` in a Period.
export type IManifestAdaptations = Partial<Record<IAdaptationType, Adaptation[]>>;

export type IAdaptationsArguments =
  Partial<Record<IAdaptationType, IAdaptationArguments[]>>;

// Arguments constitutive of a new Period.
export interface IPeriodArguments {
  // required
  id : string; // unique ID for that Period.
  adaptations : IAdaptationsArguments; // "Tracks" in that Period.
  start : number; // start time of the Period, in seconds.

  // optional
  duration? : number; // duration of the Period, in seconds.
                      // Can be undefined for a still-running one.
}

/**
 * Class representing a single `Period` of the Manifest.
 * A Period contains every informations about the content available for a
 * specific period in time.
 * @class Period
 */
export default class Period {
  /**
   * ID uniquely identifying the Period in the Manifest.
   * @type {string}
   */
  public readonly id : string;

  /**
   * Every 'Adaptation' in that Period, per type of Adaptation.
   * @type {Object}
   */
  public adaptations : IManifestAdaptations;

  /**
   * Duration of this Period, in seconds.
   * `undefined` for still-running Periods.
   * @type {number|undefined}
   */
  public duration? : number;

  /**
   * Absolute start time of the Period, in seconds.
   * @type {number}
   */
  public start : number;

  /**
   * Absolute end time of the Period, in seconds.
   * `undefined` for still-running Periods.
   * @type {number|undefined}
   */
  public end? : number;

  /**
   * Array containing every errors that happened when the Period has been
   * created, in the order they have happened.
   * @type {Array.<Error>}
   */
  public readonly parsingErrors : Array<Error|ICustomError>;

  /**
   * @constructor
   * @param {Object} args
   * @param {function|undefined} [representationFilter]
   */
  constructor(
    args : IPeriodArguments,
    representationFilter? : IRepresentationFilter
  ) {
    this.parsingErrors = [];
    this.id = args.id;
    this.adaptations =
      (Object.keys(args.adaptations) as IAdaptationType[])
        .reduce<IManifestAdaptations>((acc, type) => {
          if (args.adaptations[type]) {
            const adaptationsForType = args.adaptations[type];
            if (adaptationsForType) {
              const filteredAdaptations = adaptationsForType
                .filter((adaptation) => {
                  if (!arrayIncludes(SUPPORTED_ADAPTATIONS_TYPE, adaptation.type)) {
                    log.info("not supported adaptation type", adaptation.type);
                    this.parsingErrors.push(
                      new MediaError("MANIFEST_UNSUPPORTED_ADAPTATION_TYPE", null, false)
                    );
                    return false;
                  } else {
                    return true;
                  }
                })
                .map((adaptation) => {
                  const newAdaptation =
                    new Adaptation(adaptation, representationFilter);
                  this.parsingErrors.push(...newAdaptation.parsingErrors);
                  return newAdaptation;
                })
                .filter((adaptation) => adaptation.representations.length);
              if (
                filteredAdaptations.length === 0 &&
                adaptationsForType.length > 0 &&
                (type === "video" || type === "audio")
              ) {
                const error = new Error("No supported " + type + " adaptations");
                throw new MediaError("MANIFEST_PARSE_ERROR", error, true);
              }
              acc[type] = filteredAdaptations;
            }
          }
          return acc;
        }, {});

    if (
      (!this.adaptations.video || !this.adaptations.video.length) &&
      (!this.adaptations.audio || !this.adaptations.audio.length)
    ) {
      const error = new Error("No supported audio and video adaptations.");
      throw new MediaError("MANIFEST_PARSE_ERROR", error, true);
    }

    this.duration = args.duration;
    this.start = args.start;

    if (this.duration != null && this.start != null) {
      this.end = this.start + this.duration;
    }
  }

  /**
   * Returns every `Adaptations` (or `tracks`) linked to that Period, in an
   * Array.
   * @returns {Array.<Object>}
   */<commit_msg>manifest: improve error message<commit_after>/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import arrayFind from "array-find";
import { ICustomError } from "../errors";
import MediaError from "../errors/MediaError";
import log from "../log";
import arrayIncludes from "../utils/array-includes";
import Adaptation, {
  IAdaptationArguments,
  IAdaptationType,
  IRepresentationFilter,
  SUPPORTED_ADAPTATIONS_TYPE,
} from "./adaptation";

// Structure listing every `Adaptation` in a Period.
export type IManifestAdaptations = Partial<Record<IAdaptationType, Adaptation[]>>;

export type IAdaptationsArguments =
  Partial<Record<IAdaptationType, IAdaptationArguments[]>>;

// Arguments constitutive of a new Period.
export interface IPeriodArguments {
  // required
  id : string; // unique ID for that Period.
  adaptations : IAdaptationsArguments; // "Tracks" in that Period.
  start : number; // start time of the Period, in seconds.

  // optional
  duration? : number; // duration of the Period, in seconds.
                      // Can be undefined for a still-running one.
}

/**
 * Class representing a single `Period` of the Manifest.
 * A Period contains every informations about the content available for a
 * specific period in time.
 * @class Period
 */
export default class Period {
  /**
   * ID uniquely identifying the Period in the Manifest.
   * @type {string}
   */
  public readonly id : string;

  /**
   * Every 'Adaptation' in that Period, per type of Adaptation.
   * @type {Object}
   */
  public adaptations : IManifestAdaptations;

  /**
   * Duration of this Period, in seconds.
   * `undefined` for still-running Periods.
   * @type {number|undefined}
   */
  public duration? : number;

  /**
   * Absolute start time of the Period, in seconds.
   * @type {number}
   */
  public start : number;

  /**
   * Absolute end time of the Period, in seconds.
   * `undefined` for still-running Periods.
   * @type {number|undefined}
   */
  public end? : number;

  /**
   * Array containing every errors that happened when the Period has been
   * created, in the order they have happened.
   * @type {Array.<Error>}
   */
  public readonly parsingErrors : Array<Error|ICustomError>;

  /**
   * @constructor
   * @param {Object} args
   * @param {function|undefined} [representationFilter]
   */
  constructor(
    args : IPeriodArguments,
    representationFilter? : IRepresentationFilter
  ) {
    this.parsingErrors = [];
    this.id = args.id;
    this.adaptations =
      (Object.keys(args.adaptations) as IAdaptationType[])
        .reduce<IManifestAdaptations>((acc, type) => {
          if (args.adaptations[type]) {
            const adaptationsForType = args.adaptations[type];
            if (adaptationsForType) {
              const filteredAdaptations = adaptationsForType
                .filter((adaptation) => {
                  if (!arrayIncludes(SUPPORTED_ADAPTATIONS_TYPE, adaptation.type)) {
                    log.info("not supported adaptation type", adaptation.type);
                    this.parsingErrors.push(
                      new MediaError("MANIFEST_UNSUPPORTED_ADAPTATION_TYPE", null, false)
                    );
                    return false;
                  } else {
                    return true;
                  }
                })
                .map((adaptation) => {
                  const newAdaptation =
                    new Adaptation(adaptation, representationFilter);
                  this.parsingErrors.push(...newAdaptation.parsingErrors);
                  return newAdaptation;
                })
                .filter((adaptation) => adaptation.representations.length);
              if (
                filteredAdaptations.length === 0 &&
                adaptationsForType.length > 0 &&
                (type === "video" || type === "audio")
              ) {
                const error = new Error("No supported " + type + " adaptations");
                throw new MediaError("MANIFEST_PARSE_ERROR", error, true);
              }
              acc[type] = filteredAdaptations;
            }
          }
          return acc;
        }, {});

    if (
      (!this.adaptations.video || !this.adaptations.video.length) &&
      (!this.adaptations.audio || !this.adaptations.audio.length)
    ) {
      const error = new Error("No supported audio and video tracks.");
      throw new MediaError("MANIFEST_PARSE_ERROR", error, true);
    }

    this.duration = args.duration;
    this.start = args.start;

    if (this.duration != null && this.start != null) {
      this.end = this.start + this.duration;
    }
  }

  /**
   * Returns every `Adaptations` (or `tracks`) linked to that Period, in an
   * Array.
   * @returns {Array.<Object>}
   */
{'fraction_non_alphanumeric': 0.10701804099367149, 'fraction_numerical': 0.0018891092849721357, 'mean_word_length': 2.367684478371501, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1965955', 'n_tokens_mistral': 2967, 'n_tokens_neox': 2810, 'n_words': 869}