Skip to content

Commit

Permalink
fix merge conflict?
Browse files Browse the repository at this point in the history
paulhiggs committed Nov 6, 2024
2 parents b504ca7 + f375117 commit fd903f3
Showing 35 changed files with 3,450 additions and 745 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Publish Docker image

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: true

- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Build Docker image
run: |
repo_name=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
docker build -t ghcr.io/${repo_name}/dvb-i-tools:latest .
- name: Push Docker image to GitHub Container Registry
run: |
repo_name=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
docker push ghcr.io/${repo_name}/dvb-i-tools:latest
134 changes: 134 additions & 0 deletions CMCD.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/**
* CMCD.js
*
* Definitions and check related to CMCD
*
*/

import { dvbi } from "./DVB-I_definitions.js";
import { CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE, CMCD_MODE_INTERVAL } from "./DVB-I_definitions.js";
import { APPLICATION, WARNING } from "./error_list.js";
import { isIn } from "./utils.js";

export const CMCD_keys = {
encoded_bitrate: "br",
buffer_length: "bl",
buffer_starvation: "bs",
buffer_starvation_duration: "bsd",
cdn_id: "cdn",
content_id: "cid",
object_duration: "d",
deadline: "dl",
live_stream_latency: "ltc",
measured_throughput: "mtp",
next_object_request: "nor",
next_range_request: "nrr",
object_type: "ot",
playback_rate: "pr",
requested_maximum_throughput: "rtp",
response_code: "rc",
streaming_format: "sf",
session_id: "sid",
interstitial: "int",
state: "sta",
stream_type: "st",
startup: "su",
time_to_first_byte: "ttfb",
time_to_first_body_byte: "ttfbb",
time_to_last_byte: "ttlb",
timestamp: "ts",
top_encoded_bitrate: "tb",
lowest_encoded_bitrate: "lb",
top_aggregated_encoded_bitrate: "tab",
lowest_aggregated_encoded_bitrate: "lab",
request_url: "url",
playhead_position: "pp",
player_error_code: "ec",
media_start_delay: "msd",
cmcd_version: "v",
};

const all_reporting_modes = [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE, CMCD_MODE_INTERVAL];
const CMCDv1_keys = [
{ key: CMCD_keys.encoded_bitrate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.buffer_length, allow_modes: all_reporting_modes },
{ key: CMCD_keys.buffer_starvation, allow_modes: all_reporting_modes },
{ key: CMCD_keys.content_id, allow_modes: all_reporting_modes },
{ key: CMCD_keys.object_duration, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.deadline, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.measured_throughput, allow_modes: all_reporting_modes },
{ key: CMCD_keys.next_object_request, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.next_range_request, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.object_type, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.playback_rate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.requested_maximum_throughput, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.streaming_format, allow_modes: all_reporting_modes },
{ key: CMCD_keys.session_id, allow_modes: all_reporting_modes },
{ key: CMCD_keys.stream_type, allow_modes: all_reporting_modes },
{ key: CMCD_keys.startup, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.top_encoded_bitrate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.cmcd_version, allow_modes: all_reporting_modes },
];

const CMCDv2_keys = CMCDv1_keys.concat([
{ key: CMCD_keys.buffer_starvation_duration, allow_modes: [CMCD_MODE_REQUEST, CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.cdn_id, allow_modes: all_reporting_modes },
{ ley: CMCD_keys.live_stream_latency, allow_modes: all_reporting_modes },
{ key: CMCD_keys.response_code, allow_modes: [CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.interstitial, allow_modes: [] },
{ key: CMCD_keys.state, allow_modes: all_reporting_modes },
{ key: CMCD_keys.time_to_first_byte, allow_modes: [CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.time_to_first_body_byte, allow_modes: [CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.time_to_last_byte, allow_modes: [CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.timestamp, allow_modes: all_reporting_modes },
{ key: CMCD_keys.lowest_encoded_bitrate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.top_aggregated_encoded_bitrate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.lowest_aggregated_encoded_bitrate, allow_modes: all_reporting_modes },
{ key: CMCD_keys.request_url, allow_modes: [CMCD_MODE_RESPONSE] },
{ key: CMCD_keys.playhead_position, allow_modes: all_reporting_modes },
{ key: CMCD_keys.player_error_code, allow_modes: all_reporting_modes },
{ key: CMCD_keys.media_start_delay, allow_modes: all_reporting_modes },
]);

const isCustomKey = (key) => key.includes("-");
const reportingMode = (mode) => (mode.includes(":") ? mode.substring(mode.lastIndexOf(":") + 1) : "***");

export function checkCMCDkeys(CMCD, errs, errCode) {
if (!CMCD) {
errs.addError({ type: APPLICATION, code: `${errCode}-00`, message: "checkCMCDkeys() called with CMCD=null" });
return;
}
const keys = CMCD.attr(dvbi.a_enabledKeys)?.value().split(" ");
const reporting_mode = CMCD.attr(dvbi.a_reportingMode).value();
if (keys) {
keys.forEach((key) => {
const reserved_key = CMCDv1_keys.find((e) => e.key == key);
if (reserved_key) {
if (!isIn(reserved_key.allow_modes, reporting_mode))
errs.addError({
code: `${errCode}-01`,
message: `${key.quote()} is not allowed for the specified reporting mode (${reportingMode(reporting_mode)})`,
fragment: CMCD,
});
} else if (isCustomKey(key))
errs.addError({
type: WARNING,
code: `${errCode}-02`,
message: `custom CMCD key ${key.quote()} in use`,
fragment: CMCD,
});
else
errs.addError({
code: `${errCode}-03`,
message: `${key.quote()} is not a reserved CMCDv1 key or the correct format for a custom key`,
fragment: CMCD,
});
});
}
if (reporting_mode == CMCD_MODE_INTERVAL && !isIn(keys, CMCD_keys.timestamp))
errs.addError({
code: `${errCode}-04`,
message: `the key ${CMCD_keys.timestamp.quote()} is required to be specified for ${reportingMode(reporting_mode)} reporting`,
fragment: CMCD,
});
}
23 changes: 21 additions & 2 deletions DVB-I_definitions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* DVB-I_defintions.js
*
*
* Defintions made in DVB A177 Bluebooks
*/
import { tva, tvaEA, tvaEC, TVA_CSmetadata } from "./TVA_definitions.js";
@@ -9,7 +9,6 @@ const DVB_metadata = "urn:dvb:metadata";
const DVB_CSmetadata = `${DVB_metadata}:cs`,
FVC_CSmetadata = "urn:fvc:metadata:cs";


const PaginationPrefix = `${FVC_CSmetadata}:HowRelatedCS:2015-12:pagination`,
NowNextCRIDPrefix = "crid://dvb.org/metadata/schedules/now-next";

@@ -35,6 +34,14 @@ const HbbTVStandardPrefix = "urn:hbbtv:appinformation:standardversion:hbbtv";
const HbbTVFeaturePrefix = "urn:hbbtv:appinformation:optionalfeature:hbbtv";
const CTAStandardPrefix = "urn:cta:wave:appinformation:standardversion";

const CMCDterm = `${DVB_metadata}:cmcd`;
export const CMCD_MODE_REQUEST = `${CMCDterm}:delivery:request`,
CMCD_MODE_RESPONSE = `${CMCDterm}:delivery:response`,
CMCD_MODE_INTERVAL = `${CMCDterm}:delivery:interval`;

export const CMCD_METHOD_HTTP_HEADER = `${CMCDterm}:delivery:customHTTPHeader`,
CMCD_METHOD_QUERY_ARGUMENT = `${CMCDterm}:delivery:queryArguments`;

export const dvbi = {
A177_Namespace: `${DVB_metadata}:servicediscovery:2019`,
A177r1_Namespace: `${DVB_metadata}:servicediscovery:2020`,
@@ -43,6 +50,7 @@ export const dvbi = {
A177r4_Namespace: `${DVB_metadata}:servicediscovery:2022b`,
A177r5_Namespace: `${DVB_metadata}:servicediscovery:2023`,
A177r6_Namespace: `${DVB_metadata}:servicediscovery:2024`,
A177r7_Namespace: `${DVB_metadata}:servicediscovery:2025`,

ApplicationStandards: [
`${HbbTVStandardPrefix}:1.2.1`,
@@ -164,6 +172,12 @@ export const dvbi = {
APP_OUTSIDE_AVAILABILITY: `${LINKED_APLICATION_CS}:2`,
APP_SERVICE_PROVIDER: `${LINKED_APLICATION_CS}:3`,

// A177r7
APP_IN_SERIES: `${LINKED_APLICATION_CS}:1.3`,
APP_LIST_INSTALLATION: `${LINKED_APLICATION_CS}:4.1`,
APP_WITHDRAW_AGREEMENT: `${LINKED_APLICATION_CS}:4.2`,
APP_RENEW_AGREEMENT: `${LINKED_APLICATION_CS}:4.3`,

NVOD_MODE_REFERENCE: "reference",
NVOD_MODE_TIMESHIFTED: "timeshifted",

@@ -180,6 +194,7 @@ export const dvbi = {
a_Address: "Address",
a_CGSID: "CGSID",
a_channelNumber: "channelNumber",
a_contentId: "contentId",
a_contentLanguage: tva.a_contentLanguage,
a_contentType: tva.a_contentType,
a_controlRemoteAccessOverInternet: "controlRemoteAccessOverInternet",
@@ -202,6 +217,7 @@ export const dvbi = {
a_dvb_ssrc_upstream_client: "dvb-ssrc-upstream-client",
a_dvb_t_wait_max: "dvb-t-wait-max",
a_dvb_t_wait_min: "dvb-t-wait-min",
a_enabledKeys: "enabledKeys",
a_encryptionScheme: "encryptionScheme",
a_endTime: "endTime",
a_extensionName: "extensionName",
@@ -228,6 +244,8 @@ export const dvbi = {
a_region: "region",
a_regionID: "regionID",
a_regulatorListFlag: "regulatorListFlag",
a_reportingMethod: "reportingMethod",
a_reportingMode: "reportingMode",
a_responseStatus: "responseStatus",
a_rtcp_bandwidth: "rtcp-bandwidth",
a_rtcp_mux: "rtcp-mux",
@@ -260,6 +278,7 @@ export const dvbi = {
e_Availability: "Availability",
e_CASystemId: "CASystemId",
e_ChannelBonding: "ChannelBonding",
e_CMCD: "CMCD",
e_CNAME: "CNAME",
e_Colorimetry: "Colorimetry",
e_ContentAttributes: "ContentAttributes",
41 changes: 19 additions & 22 deletions IANA_languages.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* IANA_languages.js
*
*
* Load and check language identifiers
*/
import { readFile, readFileSync } from "fs";
@@ -9,7 +9,7 @@ import chalk from "chalk";

import { datatypeIs } from "./phlib/phlib.js";

import { handleErrors } from "./fetch_err_handler.js";
import handleErrors from "./fetch_err_handler.js";
import { isIn, isIni } from "./utils.js";
import { isHTTPURL } from "./pattern_checks.js";
import fetchS from "sync-fetch";
@@ -46,6 +46,9 @@ export default class IANAlanguages {
stats(res) {
res.numLanguages = this.#languagesList.length;
res.numRedundantLanguages = this.#redundantLanguagesList.length;
let t = [];
this.#redundantLanguagesList.forEach((e) => t.push(`${e.tag}${e.preferred ? `~${e.preferred}` : ""}`));
res.RedundantLanguages = t.join(", ");
res.numLanguageRanges = this.#languageRanges.length;
res.numSignLanguages = this.#signLanguagesList.length;
if (this.#languageFileDate) res.languageFileDate = this.#languageFileDate;
@@ -66,9 +69,7 @@ export default class IANAlanguages {
* @return {boolean} true if the language subtag is a sign language
*/
function isSignLanguage(items) {
for (let i = 0; i < items.length; i++)
if (items[i].startsWith("Description") && items[i].toLowerCase().includes("sign"))
return true;
for (let i = 0; i < items.length; i++) if (items[i].startsWith("Description") && items[i].toLowerCase().includes("sign")) return true;
return false;
}

@@ -141,9 +142,8 @@ export default class IANAlanguages {
} else console.log(chalk.red(`error loading languages ${err}`));
}.bind(this)
);
}
else {
let langs = readFileSync(languagesFile, { encoding: "utf-8" } ).toString();
} else {
let langs = readFileSync(languagesFile, { encoding: "utf-8" }).toString();
this.#processLanguageData(langs);
}
}
@@ -161,7 +161,7 @@ export default class IANAlanguages {

if (purge) this.empty();

if (async)
if (async)
fetch(languagesURL)
.then(handleErrors)
.then((response) => response.text())
@@ -175,14 +175,13 @@ export default class IANAlanguages {
console.log(chalk.red(error.message));
}
if (resp) {
if (resp.ok)
this.#processLanguageData(response.text);
else console.log(chalk.red(`error (${error}) retrieving ${languagesURL}`));
if (resp.ok) this.#processLanguageData(resp.text);
else console.log(chalk.red(`error (${resp.error}) retrieving ${languagesURL}`));
}
}
}

loadLanguages(options, async=true) {
loadLanguages(options, async = true) {
if (!options) options = {};
if (!Object.prototype.hasOwnProperty.call(options, "purge")) options.purge = false;

@@ -202,6 +201,13 @@ export default class IANAlanguages {
if (datatypeIs(value, "string")) {
if (this.#languageRanges.find((range) => range.start <= value && value <= range.end)) return { resp: this.languageKnown };

let found = this.#redundantLanguagesList.find((e) => e.tag.toLowerCase() == value.toLowerCase());
if (found) {
let res = { resp: this.languageRedundant };
if (found?.preferred) res.pref = found.preferred;
return res;
}

if (value.indexOf("-") != -1) {
let matches = true;
let parts = value.split("-");
@@ -213,15 +219,6 @@ export default class IANAlanguages {

if (isIni(this.#languagesList, value)) return { resp: this.languageKnown };

let lc = value.toLowerCase();
let found = this.#redundantLanguagesList.find((e) => e.tag.toLowerCase() == lc);
if (found) {
let res = { resp: this.languageRedundant };
if (found?.preferred) res.pref = found.preferred;
[];
return res;
}

return { resp: this.languageUnknown };
}
return { resp: this.languageInvalidType };
Loading

0 comments on commit fd903f3

Please sign in to comment.