パッケージの依存関係を追加する
手順3: EPG同期タスクを定義する
次のファイルをアプリパッケージに追加し、最新のEPGデータをシステムにプッシュするビジネスロジックを定義します。詳細なガイダンスについては、EPG統合のベストプラクティスを参照してください。
アプリログを検索することによって手順を検証できます。
loggingctl log --follow | grep "epg:\|ktf:\|ktf.\|EpgSync"
手順1: アプリのタスクを定義する
srcフォルダにEpgSyncTask.tsファイルを作成して、アプリのEPG同期タスクを定義します。以下のスケルトンコードをチャンネルの統合ロジックとして使用できます。
import {
ChannelDescriptorBuilder,
ChannelInfoBuilder,
ChannelLineupProvider,
ChannelMetadataBuilder,
EpgLineupInformation,
ExternalIdBuilder,
IChannelInfo,
IExternalId,
IProgram,
InvalidArgumentError,
} from '@amazon-devices/kepler-epg-provider';
const getLatestChannelLineupVersion = () => {
// TODO: バックエンドから最新のチャンネルラインナップのバージョンを照会します。
return '1.0';
};
// 「progressCallback」パラメーターは、統合の進捗状況のフィードバックを
// 提供するために使用されます。これは、後で追加するチャンネル提供元の同期の
// 統合で使用されます。
export const ingestChannelLineup = async (progressCallback?: (percent: number) => void): Promise<void> => {
try {
// 手順1: 最新のEPGチャンネルラインナップのバージョンを
// EpgLineupInformation.getLastCommittedChannelLineupVersion()と比較します。
const lastCommitedVersion =
await EpgLineupInformation.getLastCommittedChannelLineupVersion();
const latestVersion = getLatestChannelLineupVersion();
if (lastCommitedVersion === latestVersion) {
// チャンネルラインナップに変更がないため、更新の必要はありません。
console.info(
`最新のチャンネルラインナップのバージョン(${latestVersion})が最後にコミットされたバージョン(${lastCommitedVersion})と同じです。同期をスキップします。`,
);
return;
}
// 手順2: バージョンが一致しない場合は、ユーザーに視聴権限があるチャンネル
// ラインナップを小さいページに分けてダウンロードし、ペイロードを段階的に解析して、
// ChannelLineupProviderインターフェイスを使用してラインナップを設定します。
const channels_page_1 = getChannelData(1, 10);
await ChannelLineupProvider.add(channels_page_1);
if (progressCallback) {
// TODO: EPG同期の進行状況の割合を計算します。
progressCallback(25);
}
// TODO: 上記と同じ方法で残りのチャンネルを追加します。
if (progressCallback) {
// TODO: EPG同期の進行状況の割合を計算します。
progressCallback(50);
}
// 手順3: ChannelLineupProvider.commitを使用してチャンネルラインナップをコミットします。
await ChannelLineupProvider.commit(latestVersion);
} catch (error) {
if (error instanceof InvalidArgumentError) {
// TODO: エラーメッセージをキャッチし、バックエンドにプッシュして、問題をすばやく解決します。
// エラーメッセージには、失敗した挿入の合計数と、失敗した最初の5つのチャンネルの理由が含まれます。
console.error(
`EpgSync - InvalidArgumentErrorが原因でチャンネルラインナップの統合に失敗しました:${error}`,
);
} else {
// TODO: エラーをログに記録します。Amazonの担当者と協力してエラーを修正できるように、これらのエラーをバックエンドに伝達することも検討してください。
console.error(
`EpgSync - チャンネルランナップの統合中にエラーが発生しました:${error}`,
);
}
throw error;
}
};
const getChannelData = (start_num: number, end_num: number): IChannelInfo[] => {
// TODO: 実際のチャンネルデータを追加します。
const channels_list: IChannelInfo[] = [];
for (let i = start_num; i <= end_num; i++) {
const identifier = `チャンネル${i}`;
const name = `チャンネル${i}`;
const descriptor = new ChannelDescriptorBuilder()
.identifier(identifier)
.majorNumber(0)
.minorNumber(0)
.build();
const external_id_list: IExternalId[] = [];
let external_id = new ExternalIdBuilder()
.idType('type')
.value('value')
.build();
external_id_list.push(external_id);
const metadata = new ChannelMetadataBuilder()
.name(name)
.channelType(3)
.externalIdList(external_id_list)
.build();
const channel = new ChannelInfoBuilder()
.channelDescriptor(descriptor)
.channelMetadata(metadata)
.build();
channels_list.push(channel);
}
return channels_list;
};
const doTask = async (): Promise<void> => {
console.info('EpgSyncタスクを開始します。');
await ingestChannelLineup();
// EPG同期タスクで番組データを提供する場合は、番組ラインナップの統合を追加します。
// ProgramLineupProviderを使用して番組を更新する前に、必要に応じて新しいチャンネルラインナップのcommitを実行します。
// チャンネルと番組の更新を交互に行うことはできません。
// await ingestProgramLineup();
// ライブイベントを提供する場合は、ライブイベントの統合を追加します。
// await ingestLiveEventLineup();
// チャンネルと番組のラインナップの統合中にエラーがスローされなければ、
// EPG同期タスクは正常に完了したことになります。
console.info('EpgSyncが正常に完了しました。');
};
手順2: EPG同期タスクに番組データを提供する
EPG同期タスクに番組データを提供するには、以下のスケルトンコードを番組の統合ロジックとして使用できます。カタログをAmazonカタログサービスやGracenoteなどのクラウドサービスと統合している場合は、これを実行する必要はありません。
import {
IProgram,
IUpsertProgramFailure,
ProgramBuilder,
ProgramLineupProvider2,
} from '@amazon-devices/kepler-epg-provider';
const getLatestProgramLineupVersion = () => {
// TODO: バックエンドから最新の番組ラインナップのバージョンを照会します。
return '1.0';
};
// 「progressCallback」パラメーターは、統合の進捗状況のフィードバックを
// 提供するために使用されます。これは、後で追加するチャンネル提供元の同期の
// 統合で使用されます。
export const ingestProgramLineup = async (progressCallback?: (percent: number) => void): Promise<void> => {
try {
// 手順1: 最新のEPG番組ラインナップのバージョンを
// EpgLineupInformation.getLastCommittedProgramLineupVersion()と比較します。
const lastCommitedVersion =
await EpgLineupInformation.getLastCommittedProgramLineupVersion();
const latestVersion = getLatestProgramLineupVersion();
if (lastCommitedVersion === latestVersion) {
// 最後にコミットされた番組ラインナップに変更がないため、更新の必要はありません。
console.info(
`最新の番組ラインナップのバージョン(${latestVersion})が最後にコミットされたバージョン(${lastCommitedVersion})と同じです。同期をスキップします。`,
);
return;
}
// 任意の手順: 誤って追加された番組を電子番組表(EPG)から削除する必要がある場合に限り、
// clearAllPrograms()を使用します。これによってデータストアからチャンネル情報が消去されることはありません。
// clearAllPrograms()関数呼び出しは、同じトランザクション内でupsert()を呼び出す前に実行する必要があります。
// ProgramLineupProviderのアクションは、commit()が呼び出されるまで永続化されません。
// 手順2: バージョンが一致しない場合は、番組ラインナップを小さいページに分けて
// 分けてダウンロードし、段階的に解釈して、ProgramLineupProviderインターフェイスを
// 使用してラインナップを設定します。
// 番組のChannelDescriptorに対応するチャンネルがコミットされていない場合、
// ProgramLineupProvider2.upsert操作は失敗します。
const programs_page_1 = getProgramData(1, 10);
const upsertProgramFailures_page_1 = await ProgramLineupProvider2.upsert(
programs_page_1,
);
if (upsertProgramFailures_page_1.length > 0) {
// TODO: 失敗した番組の情報をすべてキャッチし、バックエンドにプッシュして、番組データの問題をすばやく解決します。
console.error(
`EpgSync - 1ページ目でアップサートに失敗した番組が${upsertProgramFailures_page_1.length}個あります。`,
);
processUpsertProgramFailures(upsertProgramFailures_page_1);
// TODO: 残りの番組のアップサートを続けるか、番組の統合プロセスを中止するかを選択できます。
// throw Error(
// '1ページ目の番組データが無効なため、番組の統合プロセスを中止します',
// );
}
if (progressCallback) {
// TODO: EPG同期の進行状況の割合を計算します。
progressCallback(75);
}
// TODO: 上記と同じ方法で残りの番組をアップサートします。
if (progressCallback) {
// TODO: EPG同期の進行状況の割合を計算します。
progressCallback(100);
}
// 手順3: ProgramLineupProvider2.commitを使用して番組ラインナップをコミットします。
const total_program_failures =
upsertProgramFailures_page_1.length + upsertProgramFailures_page_2.length;
console.info(
`EpgSync - エラーのあった番組の合計数:${total_program_failures}`,
);
// TODO: いずれかの番組のアップサートに失敗し、それらのエラーを受け取ったときにプロセスを中止しなかった場合は、
// 正常にアップサートされた番組のlatestVersionを更新し、失敗した番組については情報をバックエンドに送信して、
// 次回の同期までに修正できます。
await ProgramLineupProvider2.commit(latestVersion);
} catch (error) {
// TODO: エラーをログに記録します。Amazonの担当者と協力してエラーを修正できるように、これらのエラーをバックエンドに伝達することも検討してください。
console.error(`EpgSync - 番組ランナップの統合中にエラーが発生しました:${error}`);
throw error;
}
};
const getProgramData = (
channel_start_num: number,
channel_end_num: number,
): IProgram[] => {
// TODO: 実際の番組データを追加します。以下のサンプルコードでは、現在の時刻から始まるダミーの番組を作成します。
const programs_list: IProgram[] = [];
const current_time = Date.now();
for (let i = channel_start_num; i <= channel_end_num; i++) {
const identifier = `チャンネル${i}`;
const descriptor = new ChannelDescriptorBuilder()
.identifier(identifier)
.majorNumber(0)
.minorNumber(0)
.build();
// 最初の番組は現在のシステム時刻の45分前から始まります。
var temp_time = current_time - 45 * 60 * 1000;
// 各チャンネルに50個の番組を追加します。
for (let j = 1; j <= 50; j++) {
const start_time = temp_time;
const end_time = start_time + 60 * 60 * 1000; // 60分をミリ秒で表した値
const program_title = `番組${j}`;
const program = new ProgramBuilder()
.identifier(`番組${j}`)
.channelDescriptor(descriptor)
.title(program_title)
.startTimeMs(start_time)
.endTimeMs(end_time)
.build();
programs_list.push(program);
temp_time = end_time;
}
}
return programs_list;
};
// TODO: 失敗した番組の情報をログに追加し、バックエンドにアップロードして、無効なデータをすばやく修正します。
const processUpsertProgramFailures = (
upsertProgramFailures: IUpsertProgramFailure[],
): void => {
upsertProgramFailures.forEach((element: IUpsertProgramFailure) => {
const program = element.program;
const program_id = program.identifier;
const channel = element.program.channelDescriptor;
const err =
element.error.message === undefined ? '' : element.error.message;
console.error(
`EpgSyncで、IDが${program_id}の番組(所属するチャンネルID:${channel.identifier})のアップサートに失敗しました。エラーメッセージ:${err}`,
);
});
};
手順3: ライブイベントデータを提供する
ライブイベントを提供する場合は、まずライブイベントについてを参照してください。その後、以下のスケルトンコードをライブイベントの統合ロジックとして使用できます。
import {
EventType,
IAddLiveEventFailure,
ILiveEvent,
LiveEventBuilder,
LiveEventProvider,
PlaybackReferenceBuilder,
PlaybackType,
} from '@amazon-devices/kepler-epg-provider';
import { MediaId } from '@amazon-devices/kepler-media-types';
const getLatestLiveEventLineupVersion = () => {
// TODO: バックエンドから最新のライブイベントラインナップのバージョンを照会します。
return '1.0';
};
const ingestLiveEventLineup = async (): Promise<void> => {
try {
// 手順1: 最新のEPGライブイベントラインナップのバージョンを
// EpgLineupInformation.getLastCommittedLiveEventLineupVersion()と比較します。
const lastCommitedVersion =
await EpgLineupInformation.getLastCommittedLiveEventLineupVersion();
const latestVersion = getLatestLiveEventLineupVersion();
if (lastCommitedVersion === latestVersion) {
// 最後にコミットされたライブイベントに変更がないため、更新の必要はありません。
console.info(
`最新のライブイベントラインナップのバージョン(${latestVersion})が最後にコミットされたバージョン(${lastCommitedVersion})と同じです。同期をスキップします。`,
);
return;
}
// 手順2: バージョンが一致しない場合は、ライブイベントラインナップを小さいページに
// 分けてダウンロードし、段階的に解釈して、LiveEventProviderインターフェイスを
// 使用してラインナップを設定します。
const live_events_page_1 = getLiveEventData(1, 10);
const addLiveEventFailures_page_1 = await LiveEventProvider.add(
live_events_page_1,
);
if (addLiveEventFailures_page_1.length > 0) {
// TODO: 失敗したライブイベントの情報をすべてキャッチし、バックエンドにプッシュして、ライブイベントデータの問題をすばやく解決します。
console.error(
`EpgSync - 1ページ目から追加できなかったライブイベントが${addLiveEventFailures_page_1.length}個あります`,
);
processAddLiveEventFailures(addLiveEventFailures_page_1);
// TODO: 残りのライブイベントの追加を続けるか、ライブイベントの統合プロセスを中止するかを選択できます。
// throw Error(
// '1ページ目のライブイベントデータが無効なため、ライブイベントの統合プロセスを中止します',
// );
}
// TODO: 上記と同じ方法で残りのライブイベントを追加します。
// 手順3: LiveEventProvider.commitを使用してライブイベントラインナップをコミットします。
const total_live_event_failures =
addLiveEventFailures_page_1.length + addLiveEventFailures_page_2.length;
console.info(
`EpgSync - エラーのあったライブイベントの合計数:${total_live_event_failures}`,
);
// TODO: いずれかのライブイベントの追加に失敗し、それらのエラーを受け取ったときにプロセスを中止しなかった場合は、
// 正常に追加されたライブイベントのlatestVersionを更新し、失敗したライブイベントについては情報をバックエンドに
// 送信して、次回の同期までに修正できます。
await LiveEventProvider.commit(latestVersion);
} catch (error) {
// TODO: エラーをログに記録します。Amazonの担当者と協力してエラーを修正できるように、これらのエラーをバックエンドに伝達することも検討してください。
console.error(`EpgSync - ライブイベントラインナップの統合中にエラーが発生しました:${error}`);
throw error;
}
};
const getLiveEventData = (start_num: number, end_num: number): ILiveEvent[] => {
// TODO: 実際のライブイベントデータを追加します。
const live_events_list: ILiveEvent[] = [];
for (let i = start_num; i <= end_num; i++) {
const playbackReference = new PlaybackReferenceBuilder()
.playbackType(PlaybackType.CONTENT)
.mediaId(new MediaId('contentId', 'catalogName'))
.build();
const start_time = Date.now() - 45 * 60 * 1000;
const end_time = start_time + 60 * 60 * 1000;
const live_event = new LiveEventBuilder()
.identifier(`LiveEvent${i}`)
.eventType(EventType.SCHEDULED_EVENT)
.playbackReference(playbackReference)
.startTimeMs(start_time)
.endTimeMs(end_time)
.title('タイトル')
.build();
live_events_list.push(live_event);
}
return live_events_list;
};
// TODO: 失敗したライブイベントの情報をログに追加し、バックエンドにアップロードして、無効なデータをすばやく修正します。
const processAddLiveEventFailures = (
addLiveEventFailures: IAddLiveEventFailure[],
): void => {
addLiveEventFailures.forEach((element: IAddLiveEventFailure) => {
const live_event = element.liveEvent;
const live_event_id = live_event.identifier;
const err =
element.error.message === undefined ? '' : element.error.message;
console.error(
`EpgSyncでIDが${live_event_id}のライブイベントの追加に失敗しました。エラーメッセージ:${err}`,
);
});
};
次は、指定されたガイドラインに従ってEPG同期タスクにビジネスロジックを実装します。
Last updated: 2025年9月30日

