as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

步骤3: 定义EPG同步任务

步骤3: 定义EPG同步任务

将以下文件添加到您的应用程序包中,并定义您的业务逻辑,以向系统中推送最新EPG数据。如需更多指导说明,请参阅EPG引入最佳实践

您可以通过搜索应用日志来验证这些步骤:

已复制到剪贴板。

  loggingctl log --follow | grep "epg:\|ktf:\|ktf.\|EpgSync"

步骤1: 定义应用的任务

定义应用的EPG同步任务,方法是在src文件夹中创建EpgSyncTask.ts文件。您可以将以下框架代码用于频道引入逻辑。

已复制到剪贴板。

import {
ChannelDescriptorBuilder,
ChannelInfoBuilder,
ChannelLineupProvider,
ChannelMetadataBuilder,
EpgLineupInformation,
ExternalIdBuilder,
IChannelInfo,
IExternalId,
IProgram,
InvalidArgumentError,
} from '@amazon-devices/kepler-epg-provider';

const getLatestChannelLineupVersion = () => {
  // 待办事项: 从后端查询最新的频道时间表版本。
  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) {
      // 待办事项: 计算EPG同步的进度百分比
      progressCallback(25);
    }

    // 待办事项: 使用与上面相同的方法添加其余频道。
    if (progressCallback) {
      // 待办事项: 计算EPG同步的进度百分比
      progressCallback(50);
    }

    // 步骤3: 使用ChannelLineupProvider.commit提交频道时间表
    await ChannelLineupProvider.commit(latestVersion);
  } catch (error) {
    if (error instanceof InvalidArgumentError) {
      // 待办事项: 捕获错误消息并将其推送到后端以快速解决问题。
      // 错误消息包括插入失败的总数和前5个失败频道的原因。
      console.error(
        `EpgSync - 频道时间表引入失败,原因是InvalidArgumentError:${error}`,
      );
    } else {
      // 待办事项: 记录这些错误。还可以考虑将这些错误传播到您的后端,以便与您的亚马逊联系人合作修复这些错误。
      console.error(
        `EpgSync - 频道时间表引入期间发生了错误:${error}`,
      );
    }
    throw error;
  }
};

const getChannelData = (start_num: number, end_num: number): IChannelInfo[] => {
  // 待办事项: 添加实际的频道数据。
  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之前,请提交新的频道时间表(如果需要)。
  // 频道和节目更新不能交错。
  // await ingestProgramLineup();

  // 如果您提供直播活动,请添加直播活动引入。
  // await ingestLiveEventLineup();

  // 如果在频道和节目时间表引入期间没有引发错误,
  // 则EPG同步任务会成功完成。
  console.info('EPGSync成功完成!');
};

步骤2: 在EPG同步任务中提供节目数据

要在EPG同步任务中提供节目数据,可参考以下节目引入逻辑的框架代码。如果您已将目录与云服务(例如亚马逊目录服务Gracenote)集成在一起,则无需执行此操作。

已复制到剪贴板。

import {
  IProgram,
  IUpsertProgramFailure,
  ProgramBuilder,
  ProgramLineupProvider2,
} from '@amazon-devices/kepler-epg-provider';

const getLatestProgramLineupVersion = () => {
  // 待办事项: 从后端查询最新的节目时间表版本。
  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()”的调用之前。
    // 直到调用“commit()”后,ProgramLineupProvider操作才会保留。

    // 步骤2: 如果版本不匹配,请以小型页面的形式下载节目时间表,
    // 逐步解析,并使用
    // 设置该时间表。

    // 如果未提交与节目的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) {
      // 待办事项: 捕获所有失败节目信息并将其推送到后端,以快速解决节目数据的问题。
      console.error(
        `EpgSync - 第1页有${upsertProgramFailures_page_1.length}个节目更新和插入失败`,
      );
      processUpsertProgramFailures(upsertProgramFailures_page_1);
      // 待办事项: 可以选择继续更新和插入其余节目或中止节目引入进程。
      // throw Error(
      //   '由于第1页中的节目数据无效而中止节目引入进程',
      // );
    }
    if (progressCallback) {
      // 待办事项: 计算EPG同步的进度百分比
      progressCallback(75);
    }

    // 待办事项: 使用与上面相同的方法更新和插入其余节目。

    if (progressCallback) {
      // 待办事项: 计算EPG同步的进度百分比
      progressCallback(100);
    }

    // 步骤3: 使用ProgramLineupProvider2.commit提交节目时间表
    const total_program_failures =
      upsertProgramFailures_page_1.length + upsertProgramFailures_page_2.length;

    console.info(
      `EpgSync - 出错节目总数:${total_program_failures}`,
    );

    // 待办事项: 如果有任何节目更新和插入失败,并且您在收到这些失败错误时没有中止该进程,
    // 则可以更新成功更新和插入的节目的latestVersion,并将失败节目的相关信息
    // 发送回后端,以便在下次同步之前修复这些错误。
    await ProgramLineupProvider2.commit(latestVersion);
  } catch (error) {
    // 待办事项: 记录这些错误。还可以考虑将这些错误传播到您的后端,以便与您的亚马逊联系人合作修复这些错误。
    console.error(`EpgSync - 节目时间表引入期间发生了错误:${error}`);
    throw error;
  }
};

const getProgramData = (
  channel_start_num: number,
  channel_end_num: number,
): IProgram[] => {
  // 待办事项: 添加实际的节目数据。下面的示例代码从当前时间开始创建虚构节目。
  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;
};

// 待办事项: 在日志中添加失败节目的信息并上传到后端,以快速修复无效数据。
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 = () => {
  // 待办事项: 从后端查询最新的直播活动时间表版本。
  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) {
      // 待办事项: 捕获所有失败直播活动信息并将其推送到后端,以快速解决直播活动数据的问题。
      console.error(
        `EpgSync - 页面1有${addLiveEventFailures_page_1.length}个直播活动添加失败`,
      );
      processAddLiveEventFailures(addLiveEventFailures_page_1);
      // 待办事项: 您可以选择继续添加其余直播活动或中止直播活动引入进程。
      // throw Error(
      //   '由于页面1中的直播活动数据无效而中止直播活动引入进程',
      // );
    }

    // 待办事项: 使用与上面相同的方法添加其余直播活动。

    // 步骤3: 使用LiveEventProvider.commit提交直播活动时间表
    const total_live_event_failures =
      addLiveEventFailures_page_1.length + addLiveEventFailures_page_2.length;

    console.info(
      `EpgSync - 出错直播活动的总数:${total_live_event_failures}`,
    );

    // 待办事项: 如果有任何直播活动添加失败,并且您在收到这些失败错误时没有中止该进程,
    // 则可以更新成功添加的直播活动的latestVersion,并将失败直播活动的相关信息
    // 发送回后端,以便在下次同步之前修复这些错误。
    await LiveEventProvider.commit(latestVersion);
  } catch (error) {
    // 待办事项: 记录这些错误。还可以考虑将这些错误传播到您的后端,以便与您的亚马逊联系人合作修复这些错误。
    console.error(`EpgSync - 直播活动时间表引入期间发生错误:${error}`);
    throw error;
  }
};

const getLiveEventData = (start_num: number, end_num: number): ILiveEvent[] => {
  // 待办事项: 添加实际的直播活动数据。
  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;
};

// 待办事项: 在日志中添加失败直播活动的信息并上传到后端,以快速修复无效数据。
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日