TypeScriptでPodcastのXMLを生成する方法:ローカルディレクトリとS3からMP3ファイルを取得する

カテゴリ: 未分類

Podcastの配信において、音声ファイル(MP3)とそのメタデータを使って、PodcastのRSSフィード(XML形式)を生成することがよくあります。今回は、TypeScriptを使って、ローカルディレクトリまたはAWS S3からMP3ファイルを取得し、その情報をもとにPodcastのXMLファイルを作成する方法を紹介します。

概要

  1. MP3ファイルのメタデータを取得:ファイル名、タイトル、説明、再生時間など。
  2. XML形式でPodcastのRSSフィードを生成:iTunesに適した形式でエピソード情報をXML化。
  3. ローカルディレクトリとS3バケットからMP3ファイルを取得:環境によって処理を分岐。

必要なライブラリ

以下のライブラリを使用します:

  • music-metadata:MP3ファイルのメタデータを取得します。
  • xml2js:JavaScriptオブジェクトをXMLに変換します。
  • fspath:ローカルファイルシステム操作に必要です。
  • aws-sdk:AWS S3からファイルを取得するために使用します。

まず、必要なパッケージをインストールします。

npm install fs path xml2js music-metadata aws-sdk

1. MP3ファイルのメタデータを取得

PodcastのXMLを作成するために、MP3ファイルから以下の情報を取得します:

  • タイトル:ファイルに設定されているタイトル。
  • 説明:ファイルに設定されているコメント(なければデフォルトの説明を使用)。
  • 再生時間:音声の長さ。

MP3ファイルのメタデータを取得するために、music-metadataライブラリを使います。

import musicMetadata from 'music-metadata';

const getEpisodeMetadata = async (filePath: string) => {
  try {
    const metadata = await musicMetadata.parseFile(filePath);
    const duration = metadata.format.duration;
    const hours = Math.floor(duration / 3600);
    const minutes = Math.floor((duration % 3600) / 60);
    const seconds = Math.floor(duration % 60);
    const episodeDuration = `${hours}:${minutes}:${seconds}`;

    const episodeTitle = metadata.common.title || path.basename(filePath, '.mp3');
    const episodeDescription = metadata.common.comment || `Description for episode ${episodeTitle}.`;

    return { episodeTitle, episodeDescription, episodeDuration };
  } catch (err) {
    console.error('MP3メタデータの取得に失敗しました:', err);
    return {
      episodeTitle: path.basename(filePath, '.mp3'),
      episodeDescription: `Description for episode ${path.basename(filePath, '.mp3')}.`,
      episodeDuration: '00:00:00'
    };
  }
};

2. ローカルディレクトリとS3からMP3ファイルを取得

次に、MP3ファイルをどこから取得するか決めます。今回は、ローカルディレクトリとS3からファイルを取得する方法を実装します。

ローカルディレクトリからファイルを取得

const getFilesFromLocal = (directory: string) => {
  return fs.readdirSync(directory).filter(file => file.endsWith('.mp3'));
};

S3からファイルを取得

S3にあるMP3ファイルを取得するには、AWS SDKを使用します。listObjectsV2を使って、指定したプレフィックス(ディレクトリ)にあるMP3ファイルの一覧を取得します。

import AWS from 'aws-sdk';

const s3 = new AWS.S3({
  region: 'us-west-2', // 適切なリージョンを指定
});

const getFilesFromS3 = async (bucketName: string, prefix: string) => {
  const params = {
    Bucket: bucketName,
    Prefix: prefix,
  };
  try {
    const data = await s3.listObjectsV2(params).promise();
    return data.Contents?.filter(file => file.Key?.endsWith('.mp3')).map(file => file.Key!) || [];
  } catch (err) {
    console.error('S3からファイル一覧の取得に失敗しました:', err);
    return [];
  }
};

3. PodcastのXMLを生成

MP3ファイルの情報を集めたら、それを元にPodcastのXMLを生成します。xml2jsライブラリを使用して、JSONオブジェクトからXMLを作成します。

import { Builder } from 'xml2js';

const podcastMetadata = {
  title: 'My Podcast',
  description: 'This is a description of the podcast.',
  link: process.env.PODCAST_DOMAIN || '',
  language: 'ja',
  copyright: 'Your Company',
  pubDate: new Date().toUTCString(),
  itunes: {
    author: 'Your Name',
    category: 'Technology',
    image: 'https://yourwebsite.com/podcast-image.jpg'
  }
};

const createPodcastXML = async (directory: string, isS3: boolean, bucketName?: string, prefix?: string) => {
  let files: string[] = [];
  if (isS3) {
    if (!bucketName || !prefix) {
      throw new Error('S3のバケット名とプレフィックスを指定してください');
    }
    files = await getFilesFromS3(bucketName, prefix);
  } else {
    files = getFilesFromLocal(directory);
  }

  const episodes = await Promise.all(files.map(async (file) => {
    const episodeLink = isS3
      ? `https://your-s3-bucket-name.s3.amazonaws.com/${file}`
      : `${podcastMetadata.link}/podcasts/${file}`;
    const filePath = isS3 ? file : path.join(directory, file); 

    const { episodeTitle, episodeDescription, episodeDuration } = await getEpisodeMetadata(filePath);

    return {
      title: episodeTitle,
      description: episodeDescription,
      link: episodeLink,
      enclosure: {
        $: {
          url: episodeLink,
          type: 'audio/mpeg',
          length: isS3 ? '0' : fs.statSync(filePath).size.toString()
        }
      },
      guid: episodeLink,
      pubDate: new Date().toUTCString(),
      'itunes:duration': episodeDuration
    };
  }));

  const podcastXML = {
    rss: {
      $: {
        version: '2.0',
        xmlns: 'http://www.itunes.com/dtds/podcast-1.0.dtd',
      },
      channel: [
        {
          title: podcastMetadata.title,
          description: podcastMetadata.description,
          link: podcastMetadata.link,
          language: podcastMetadata.language,
          copyright: podcastMetadata.copyright,
          pubDate: podcastMetadata.pubDate,
          'itunes:author': podcastMetadata.itunes.author,
          'itunes:category': {
            $: {
              text: podcastMetadata.itunes.category
            }
          },
          'itunes:image': {
            $: {
              href: podcastMetadata.itunes.image
            }
          },
          item: episodes
        }
      ]
    }
  };

  const builder = new Builder();
  const xml = builder.buildObject(podcastXML);

  if (!isS3) {
    fs.writeFileSync(path.join(directory, 'podcast.xml'), xml, 'utf-8');
    console.log('Podcast XMLが作成されました');
  }

  if (isS3) {
    console.log('Podcast XMLをS3にアップロードする処理を追加できます');
  }
};

4. 実行

実際にこのコードを使ってPodcastのXMLを作成する際、ローカルディレクトリからMP3ファイルを取得する場合、isS3falseに設定します。S3から取得する場合は、isS3trueに設定し、S3のバケット名とプレフィックスを指定します。

const directoryPath = './podcasts'; // ローカルディレクトリパス
const isS3 = false; // S3から取得する場合は true、ローカルから取得する場合は false
const bucketName = 'your-s3-bucket-name'; // S3バケット名
const prefix = 'podcasts/'; // S3内のディレクトリ

createPodcastXML(directoryPath, isS3, bucketName, prefix);

まとめ

このように、TypeScriptとAWS SDKを活用して、ローカルディレクトリまたはS3からMP3ファイルを取得し、それを元にPodcastのRSSフィード(XMLファイル)を生成することができます。Podcast配信の準備が整うと、配信先のサービス(iTunesやSpotifyなど)で番組を簡単に公開できるようになります。

関連記事

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です