<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>字幕 | imakat.com</title>
	<atom:link href="https://imakat.com/tag/%E5%AD%97%E5%B9%95/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Sat, 09 May 2026 21:33:07 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://i0.wp.com/imakat.com/wp-content/uploads/2023/07/cropped-80d64ecd340db4e2ca3224859b04caed.png?fit=32%2C32&#038;ssl=1</url>
	<title>字幕 | imakat.com</title>
	<link>https://imakat.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">160909258</site>	<item>
		<title>【Mac】Gemで無料でVTT字幕を生成する</title>
		<link>https://imakat.com/2026/03/26/28762/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 26 Mar 2026 11:59:19 +0000</pubDate>
				<category><![CDATA[字幕作成]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[vtt]]></category>
		<category><![CDATA[字幕]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[Gem]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=28762</guid>

					<description><![CDATA[動画の字幕作成については、これまで何度も試行錯誤を繰り返してきましたが、「これだ！」と思えるおすすめの方法を見つけました 。 今回は、Googleの生成AI（Gemini）の「Gem共有（カスタムAIエージェント）」を活 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>動画の字幕作成については、これまで何度も試行錯誤を繰り返してきましたが、「これだ！」と思えるおすすめの方法を見つけました 。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=aQFJQPda.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=aQFJQPda.png" alt="" style="aspect-ratio:1.4480358030830434;width:268px;height:auto"/></a></figure>



<p>今回は、Googleの生成AI（Gemini）の「Gem共有（カスタムAIエージェント）」を活用して、高精度なVTT字幕を生成するプログラムを作成しましたので紹介します 。</p>



<p>最大の特徴は、<strong>サブスクリプション不要（無料）で実践できる</strong>という点です 。（※Googleアカウントは必要です 。）</p>



<p>Geminiの文字起こしはマルチモーダル処理のため、精度は非常に高く、後から手直しする手間が劇的に減ります 。無料枠の制限を賢く回避しつつ、面倒な作業は、Macクイックアクションで自動化する、実践的なワークフローを公開します。</p>



<p>解説動画をご覧ください。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; /* dynamicと合わせた基本サイズ */
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  /* ★スマホ画面（幅500px以下）の時は文字を縮小して統一感を出す */
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  /* 行梱包時の基本スタイル */
  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  /* 古い枠内字幕ボックスを強制消去 */
  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=77" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=zL87WO8z.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=W9i8k8Rd.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=R5NnP7EQ.vtt" label="日本語" srclang="ja" kind="subtitles" default></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>)  〜無料でGem共有でvtt字幕生成〜<br>
(<a href="#" class="imk-cue" data-seek="0:14" translate="no">00:00:14</a>)  今回は、えーGem。Gemというのは、GoogleのAIエージェントですけれども、<br>
(<a href="#" class="imk-cue" data-seek="0:24" translate="no">00:00:24</a>)  それを使って、VTT字幕の生成を行うプログラムを作成したので紹介します。<br>
(<a href="#" class="imk-cue" data-seek="0:36" translate="no">00:00:36</a>)  動画の字幕作成については、これまで何度も取り上げてきました。<br>
(<a href="#" class="imk-cue" data-seek="0:43" translate="no">00:00:43</a>)  でもまあ、なかなかここで満足ということにはなりませんが、<br>
(<a href="#" class="imk-cue" data-seek="0:48" translate="no">00:00:48</a>)  最近これが結構おすすめという方法を見つけましたので紹介します。<br>
(<a href="#" class="imk-cue" data-seek="0:56" translate="no">00:00:56</a>)  生成AIを使う方法です。<br>
(<a href="#" class="imk-cue" data-seek="1:00" translate="no">00:01:00</a>)  サブスクなしで、お金を使わないでできる方法ですのでご心配なく。<br>
(<a href="#" class="imk-cue" data-seek="1:11" translate="no">00:01:11</a>)  ただし、Googleアカウントは必要になります。<br>
(<a href="#" class="imk-cue" data-seek="1:16" translate="no">00:01:16</a>)  まず、字幕を作りたい動画を用意します。<br>
(<a href="#" class="imk-cue" data-seek="1:21" translate="no">00:01:21</a>)  今回ですね、一つ10分弱の動画をですね用意しました。<br>
(<a href="#" class="imk-cue" data-seek="1:29" translate="no">00:01:29</a>)  VTT作成用にこの動画を分割します。<br>
(<a href="#" class="imk-cue" data-seek="1:34" translate="no">00:01:34</a>)  その理由はGeminiのGemを使うとき、特に無料アカウントで使うときは、<br>
(<a href="#" class="imk-cue" data-seek="1:42" translate="no">00:01:42</a>)  動画は5分以内という制限があるからです。<br>
(<a href="#" class="imk-cue" data-seek="1:49" translate="no">00:01:49</a>)  この動画をですね、右クリックします。<br>
(<a href="#" class="imk-cue" data-seek="1:52" translate="no">00:01:52</a>)  クイックアクション、このクイックアクションの中から、<br>
(<a href="#" class="imk-cue" data-seek="1:59" translate="no">00:01:59</a>)  あらかじめ自作した「字幕用に動画を分割する」これを選びます。<br>
(<a href="#" class="imk-cue" data-seek="2:20" translate="no">00:02:20</a>)  すると、分割する基本秒数を入れてください、と出てきます。<br>
(<a href="#" class="imk-cue" data-seek="2:28" translate="no">00:02:28</a>)  デフォルトは270秒になっています。つまり4分30秒になっています。<br>
(<a href="#" class="imk-cue" data-seek="2:36" translate="no">00:02:36</a>)  でもこれは4分30秒のところでバサッと分割するのではありません。<br>
(<a href="#" class="imk-cue" data-seek="2:44" translate="no">00:02:44</a>)  4分30秒付近で1秒間の無音になる部分を探して、<br>
(<a href="#" class="imk-cue" data-seek="2:51" translate="no">00:02:51</a>)  その無音が開始する場所で分割するようになっています。<br>
(<a href="#" class="imk-cue" data-seek="2:58" translate="no">00:02:58</a>)  分割ファイルはsplit_01_02...と、いうように分割されていきます。<br>
(<a href="#" class="imk-cue" data-seek="3:31" translate="no">00:03:31</a>)  えー、split_01、02、03と3つのファイルに分割されました。<br>
(<a href="#" class="imk-cue" data-seek="3:39" translate="no">00:03:39</a>)  で、あと一つ、offsets.txtというファイルも出来上がってます。<br>
(<a href="#" class="imk-cue" data-seek="3:46" translate="no">00:03:46</a>)  それではこのoffsets.txtというファイルを開いてみます。<br>
(<a href="#" class="imk-cue" data-seek="3:52" translate="no">00:03:52</a>)  すると、ここにですね、分割したファイルの開始時刻が入っています。<br>
(<a href="#" class="imk-cue" data-seek="4:02" translate="no">00:04:02</a>)  01、02、03、ここにズレ0秒、ズレ245.130秒<br>
(<a href="#" class="imk-cue" data-seek="4:09" translate="no">00:04:09</a>)  ズレ443.475秒となっています。<br>
(<a href="#" class="imk-cue" data-seek="4:19" translate="no">00:04:19</a>)  これは後で使うことになります。まあ、あることだけを覚えておいてください。<br>
(<a href="#" class="imk-cue" data-seek="4:25" translate="no">00:04:25</a>)  一応これを見て、確かにそのそれぞれが5分以内で分割されていることは確認できます。<br>
(<a href="#" class="imk-cue" data-seek="4:35" translate="no">00:04:35</a>)  一つ目が245秒、二つ目が、まあ200秒ぐらい、三つ目はですね、<br>
(<a href="#" class="imk-cue" data-seek="4:44" translate="no">00:04:44</a>)  全体で9分41秒、つまり9分41秒、443秒だから、えー、<br>
(<a href="#" class="imk-cue" data-seek="4:53" translate="no">00:04:53</a>)  7分、7x6=42、7分ちょっとのところで終わりますので、<br>
(<a href="#" class="imk-cue" data-seek="5:04" translate="no">00:05:04</a>)  あと残りが2分ちょっとですかね。その部分が03になるはずです。<br>
(<a href="#" class="imk-cue" data-seek="5:13" translate="no">00:05:13</a>)  確かに3つのファイルがですね、5分以内で分割されています。<br>
(<a href="#" class="imk-cue" data-seek="5:24" translate="no">00:05:24</a>)  えっと、次にですね、Gemで作ったこのVTT形式のコードを作成するプログラムですね、<br>
(<a href="#" class="imk-cue" data-seek="5:37" translate="no">00:05:37</a>)  これを開きます。これがそれです。<br>
(<a href="#" class="imk-cue" data-seek="5:45" translate="no">00:05:45</a>)  えー、このGemはですね、公開してますので、ブログにつけます。<br>
(<a href="#" class="imk-cue" data-seek="5:53" translate="no">00:05:53</a>)  モードはですね、あの、Proモードを選択してください。<br>
(<a href="#" class="imk-cue" data-seek="6:01" translate="no">00:06:01</a>)  で、下のボックス、ここにですね、今作った分割された動画をドロップします。<br>
(<a href="#" class="imk-cue" data-seek="6:11" translate="no">00:06:11</a>)  コピーアンドペーストします。まず一つ目コピー、<br>
(<a href="#" class="imk-cue" data-seek="6:18" translate="no">00:06:18</a>)  ここにペーストします。で、ここに入れるのはただこれだけです。<br>
(<a href="#" class="imk-cue" data-seek="6:30" translate="no">00:06:30</a>)  で、これでこの「Go」、送信の矢印を押してください。<br>
(<a href="#" class="imk-cue" data-seek="6:40" translate="no">00:06:40</a>)  そうすると作業が開始します。しばらく待ちます。<br>
(<a href="#" class="imk-cue" data-seek="7:33" translate="no">00:07:33</a>)  しばらく待ちますと、このようにVTTコードが出力されます。<br>
(<a href="#" class="imk-cue" data-seek="7:41" translate="no">00:07:41</a>)  これをコピーして、拡張子がVTTのファイルにペーストします。<br>
(<a href="#" class="imk-cue" data-seek="7:54" translate="no">00:07:54</a>)  えーと、これをコピーして、拡張子がVTTのファイルにペーストします。<br>
(<a href="#" class="imk-cue" data-seek="8:10" translate="no">00:08:10</a>)  あの、このVTTファイルは、あらかじめ用意しておいてください。<br>
(<a href="#" class="imk-cue" data-seek="8:17" translate="no">00:08:17</a>)  私はあの以前に作ったVTTファイルをですね、コピペして名前を変えて、<br>
(<a href="#" class="imk-cue" data-seek="8:28" translate="no">00:08:28</a>)  中身を削除して作っておきました。この３つですね。<br>
(<a href="#" class="imk-cue" data-seek="8:33" translate="no">00:08:33</a>)  それではこの01にですね、ペーストします。ここのコードをコピー。<br>
(<a href="#" class="imk-cue" data-seek="8:43" translate="no">00:08:43</a>)  えー、そして、ファイルにペースト。という形ですね。<br>
(<a href="#" class="imk-cue" data-seek="8:58" translate="no">00:08:58</a>)  保存。ということで、01番ができました。<br>
(<a href="#" class="imk-cue" data-seek="9:14" translate="no">00:09:14</a>)  同じようにしてですね、02以降も作るんですけども、<br>
(<a href="#" class="imk-cue" data-seek="9:21" translate="no">00:09:21</a>)  この同じセッションの中にですね、複数の動画があると、なかなかうまく受け付けてくれないので、<br>
(<a href="#" class="imk-cue" data-seek="9:30" translate="no">00:09:30</a>)  新しいセッションで同じことを繰り返すようにしてください。<br>
(<a href="#" class="imk-cue" data-seek="9:42" translate="no">00:09:42</a>)  こういう形で新しいセッションを開きます。そしてこの02ですね。これをコピーして、<br>
(<a href="#" class="imk-cue" data-seek="9:57" translate="no">00:09:57</a>)  貼り付けます。Proモードにして、<br>
(<a href="#" class="imk-cue" data-seek="10:12" translate="no">00:10:12</a>)  Proモードにして、送信します。<br>
(<a href="#" class="imk-cue" data-seek="10:38" translate="no">00:10:38</a>)  はい、コードができました。そしたらこれをコピーして、<br>
(<a href="#" class="imk-cue" data-seek="10:47" translate="no">00:10:47</a>)  02番のVTTファイルにペーストします。<br>
(<a href="#" class="imk-cue" data-seek="11:12" translate="no">00:11:12</a>)  同じように03番も作ります。<br>
(<a href="#" class="imk-cue" data-seek="11:39" translate="no">00:11:39</a>)  送信。<br>
(<a href="#" class="imk-cue" data-seek="11:58" translate="no">00:11:58</a>)  えーと、できましたのでコードをコピーして、<br>
(<a href="#" class="imk-cue" data-seek="12:06" translate="no">00:12:06</a>)  03VTTに貼り付けます。<br>
(<a href="#" class="imk-cue" data-seek="12:23" translate="no">00:12:23</a>)  こうして作るとお気づきのように、02以降のですね、動画の時刻は0秒からの開始になってしまっています。<br>
(<a href="#" class="imk-cue" data-seek="12:39" translate="no">00:12:39</a>)  秒ずらしの作業を行います。<br>
(<a href="#" class="imk-cue" data-seek="12:45" translate="no">00:12:45</a>)  この時に先ほど見たoffsets.txtの中の秒がずらし秒になってきます。<br>
(<a href="#" class="imk-cue" data-seek="12:58" translate="no">00:12:58</a>)  vttファイルの上で右クリックしてクイックアクションから「字幕時刻の秒ずらしを行う」を選びます。<br>
(<a href="#" class="imk-cue" data-seek="13:22" translate="no">00:13:22</a>)  ここでさっきの秒数を入れます。245.130秒。これ入れましてOKを押します。<br>
(<a href="#" class="imk-cue" data-seek="13:48" translate="no">00:13:48</a>)  timeshifted.vttができて245.130秒、つまり4分何秒かを加算したファイルができあがってます。<br>
(<a href="#" class="imk-cue" data-seek="14:13" translate="no">00:14:13</a>)  同じように03も秒ずらしを行います。今度は443.475。同じようにファイルができてます。<br>
(<a href="#" class="imk-cue" data-seek="14:51" translate="no">00:14:51</a>)  7分24秒ぐらいのところからのスタートに置き換わっています。<br>
(<a href="#" class="imk-cue" data-seek="15:04" translate="no">00:15:04</a>)  秒ずらしが済んだら結合したvttファイルを作ります。あらかじめbinded.vtt(conbined.vtt)を用意します。<br>
(<a href="#" class="imk-cue" data-seek="15:17" translate="no">00:15:17</a>)  この中に3つのvttファイルをコピペします。まず01は時刻ずれなしでそのままペーストします。<br>
(<a href="#" class="imk-cue" data-seek="15:45" translate="no">00:15:45</a>)  次に02_timeshifted.vttです。この連番以降のところをコピーして貼り付けます。<br>
(<a href="#" class="imk-cue" data-seek="16:18" translate="no">00:16:18</a>)  次に03_timeshifted.vtt、これも番号以降のところをコピーして貼り付けます。以上ですね。<br>
(<a href="#" class="imk-cue" data-seek="16:45" translate="no">00:16:45</a>)  全部1つのファイルにバインドされました。保存します。<br>
(<a href="#" class="imk-cue" data-seek="16:54" translate="no">00:16:54</a>)  ところがこれはすでにお気づきのように1からスタートした箇所が3箇所あるわけですね。<br>
(<a href="#" class="imk-cue" data-seek="17:08" translate="no">00:17:08</a>)  ここにもありますし、それから、<br>
(<a href="#" class="imk-cue" data-seek="17:15" translate="no">00:17:15</a>)  あ、ここにもあると。3箇所あります。<br>
(<a href="#" class="imk-cue" data-seek="17:18" translate="no">00:17:18</a>)  これを連番が全部通しで1番から開始するように、番号の振り直しをします。<br>
(<a href="#" class="imk-cue" data-seek="17:37" translate="no">00:17:37</a>)  このbinded.vtt(conbined.vtt)の上で右クリックして、<br>
(<a href="#" class="imk-cue" data-seek="17:41" translate="no">00:17:41</a>)  クイックアクションの中から、<br>
(<a href="#" class="imk-cue" data-seek="17:47" translate="no">00:17:47</a>)  この「字幕VTTの連番を付け直す」、これを選びます。<br>
(<a href="#" class="imk-cue" data-seek="17:58" translate="no">00:17:58</a>)  すると、renumbered.vttが出来上がります。<br>
(<a href="#" class="imk-cue" data-seek="18:07" translate="no">00:18:07</a>)  これは1番からですね。ずっと連番で、<br>
(<a href="#" class="imk-cue" data-seek="18:18" translate="no">00:18:18</a>)  67番までですか。ここまで繋がってます。<br>
(<a href="#" class="imk-cue" data-seek="18:26" translate="no">00:18:26</a>)  それで言葉遣いの修正とかテキストの修正は、ここまで形が整った後で行うのがいいと思います。<br>
(<a href="#" class="imk-cue" data-seek="18:38" translate="no">00:18:38</a>)  地味にコツコツとやる方法ではありますが、仕組みとして分かりやすいので作業のストレスは感じません。<br>
(<a href="#" class="imk-cue" data-seek="18:51" translate="no">00:18:51</a>)  この方法が優れているのは、GeminiのGem、これの文字起こしの精度が非常に高いということです。<br>
(<a href="#" class="imk-cue" data-seek="19:03" translate="no">00:19:03</a>)  手直しするところはとても少ないです。満足できると思います。<br>
(<a href="#" class="imk-cue" data-seek="19:10" translate="no">00:19:10</a>)  以上、Gemを使ったVTTコード作成の紹介でした。<br>
(<a href="#" class="imk-cue" data-seek="19:17" translate="no">00:19:17</a>)  コード類はブログ記事に掲載しますのでご利用ください。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    /* -----------------------------------------------
       1. 動画・音声の保護機能（右クリック禁止・DL防止）
       ----------------------------------------------- */
    function protectVideo() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも保護の対象に含めました
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    /* -----------------------------------------------
       2. 字幕制御＆ハイライト機能
       ----------------------------------------------- */
    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも取得できるようにしました
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video || !listContainer) return false; 

      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = "hidden";
             }
          }
        }
      } catch(e){}

      video.addEventListener("webkitbeginfullscreen", function() {
          try {
              if(video.textTracks && video.textTracks.length > 0) {
                  for(var i=0; i<video.textTracks.length; i++){
                      if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') video.textTracks[i].mode = "showing";
                  }
              }
          } catch(e){}
      });
      video.addEventListener("webkitendfullscreen", function() {
          try {
              if(video.textTracks && video.textTracks.length > 0) {
                  for(var i=0; i<video.textTracks.length; i++){
                      if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') video.textTracks[i].mode = "hidden";
                  }
              }
          } catch(e){}
      });

      var detailsEl = target.querySelector("details");
      if (detailsEl) {
          detailsEl.open = true; 
          var summaryEl = detailsEl.querySelector("summary");
          if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
      }

      if (!listContainer.dataset.formatted) {
          var html = listContainer.innerHTML;
          var lines = html.split(/<br\s*\/?>/i);
          var newHtml = "";
          for(var j=0; j<lines.length; j++) {
              if(lines[j].trim() === "") continue;
              newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
          }
          listContainer.innerHTML = newHtml;
          listContainer.dataset.formatted = "true";
      }

      function parseTs(ts){
        if(!ts) return null;
        var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
        if(p.length===2) return p[0]*60 + p[1];
        if(p.length===3) return p[0]*3600 + p[1]*60 + p[2];
        return null;
      }

      var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
      if (rootSublist) {
        rootSublist.addEventListener("click", function(e){
          var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
          if(!a) return;
          e.preventDefault();
          var sec = parseTs(a.getAttribute("data-seek"));
          if(sec==null) return;
          try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
        });
      }

      video.addEventListener("timeupdate", function(){
        var desiredMode = isSpecialMode() ? "showing" : "hidden";
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var t = parseTs(cues[i].getAttribute("data-seek"));
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    /* -----------------------------------------------
       監視タイマー
       ----------------------------------------------- */
    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    /* -----------------------------------------------
       3. 画面遷移時の停止機能
       ----------------------------------------------- */
    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202605100632550" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202605100632550"><strong><span class="marker">コードと要約</span><span class="marker">(クリック)</span></strong></label><div class="toggle-content">
<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>要約：<br><strong>「VTT作成用に動画を分割する」ワークフロー</strong>は、ユーザーが指定した基本秒数を基に、動画を無音区間で自動分割し、VTTの「秒ずらし」に役立つオフセット記録を生成します。<code>ffmpeg</code>とPythonスクリプトを連携させ、再エンコードなしで高速分割します。<br><strong>「字幕時刻の秒ずらしを行う」ワークフロー</strong>は、選択したVTTファイルの全タイムスタンプを、ユーザーが入力した秒数だけシフト（前後にずらす）させ、新しいVTTファイルを出力します。<code>awk</code>を用いて精密な時間計算を行います。<br><strong>「VTTの連番を付け直す」ワークフロー</strong>は、VTTファイル内の古い連番や不要なヘッダを削除し、字幕ブロックに正しい連番を振り直して整理されたVTTファイルを生成します。<br>これらのワークフローは、それぞれ動画の分割、字幕の時間調整、字幕ファイルの整理という異なる課題に対応し、VTT作成・管理作業を自動化・簡素化することを目的としています。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=無料アカウント向け_動画からVTTを生成する_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/12QYaKlTweyQxeHvd95UIxfLO7y0JOVOw?usp=sharing">添付の動画の音声から字幕用のvtt形式のコードを出力します(Gem共有)。<span class="fa fa-external-link external-icon anchor-icon"></span></a></td></tr><tr><td>公開スクリプトに関するお問い合わせは以下へ↓</td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/1Dp-NLSA5j5OXE3B1Ki2IaBRCvq4CGa6t?usp=sharing"><img decoding="async" src="https://imakat.com/rd.php?id=s7BMZHhB.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>
</div></div>



<h2 class="wp-block-heading">ポイント解説</h2>



<h3 class="wp-block-heading"><strong>解決すべき課題：Geminiの「5分の壁」</strong></h3>



<p>Geminiに動画を読み込ませて文字起こしをする際、特に無料アカウントでは「動画は5分以内」という制限があります 。 今回紹介するワークフローは、事前の「動画分割」と、事後の「タイムスタンプ調整（秒ずらし）」を組み合わせることで、この壁をストレスなく突破します。<br>有料会員でも使用制限を超えた時で、急いでいる場合などは、この方式は有用です。</p>



<h3 class="wp-block-heading"><strong><strong>長時間の動画からVTT字幕を生成する6つのステップ</strong></strong></h3>



<p>ここでは、例として10分弱の動画に字幕をつける手順を解説します 。</p>



<h4 class="wp-block-heading"><strong><strong>1. 動画の準備</strong></strong></h4>



<p>まずは手元に、字幕を作成したい元の動画ファイルを用意します 。</p>



<h4 class="wp-block-heading"><strong>2. 基本秒数の設定と動画の分割（クイックアクション）</strong></h4>



<p>動画を5分以内のパーツに分けます 。</p>



<ul class="wp-block-list">
<li>用意した動画を右クリックしクイックアクションから自作の「字幕用に動画を分割する」を選択します 。<br></li>



<li>分割する基本秒数を入力します（デフォルトは270秒＝4分30秒です） 。<br></li>



<li><strong>ポイント:</strong> 単純に時間でバサッと切るのではなく、指定時間付近の「1秒間の無音部分」を探し、キリの良いところで自動分割されるように工夫しています 。<br></li>



<li>実行すると、split_01、02…という分割動画と同時に、offsets.txtというファイルが生成されます 。このテキストには「245.130秒」といった分割時のズレ（累計秒数）が記録されており、後で使います 。<br></li>
</ul>



<h4 class="wp-block-heading"><strong><strong>3. Gemini（Gem）によるVTT字幕作成（手動）</strong></strong></h4>



<p>いよいよAIに文字起こしを依頼します。公開している専用のGemを使用します（※リンクは「コードと要約」に掲載します） 。</p>



<ul class="wp-block-list">
<li>Gemを開き、「Proモード」を選択します 。<br></li>



<li>下部のメッセージボックスに、分割した最初の動画（01）をドロップ（またはコピペ）して送信します 。<br></li>



<li>しばらく待つと、タイムスタンプ付きのVTTコードが出力されます 。<br></li>



<li>出力されたコードをコピーし、あらかじめ用意しておいた空のVTTファイル（例：01.vtt）にペーストして保存します 。<br></li>



<li><strong>注意点:</strong> 02以降の動画を処理する際は、AIが混乱するのを防ぐため、必ず「新しいセッション（チャット）」を開いてから同じ手順を繰り返してください 。<br></li>
</ul>



<h4 class="wp-block-heading"><strong>4. VTTの秒ずらし（クイックアクション）</strong></h4>



<p>出力された02番以降のVTTファイルは、動画の開始時刻が「0秒」にリセットされてしまっています 。これを元の時間軸に戻します。</p>



<ul class="wp-block-list">
<li>対象のVTTファイル（02など）を右クリックし、クイックアクションから「字幕時刻の秒ずらしを行う」を選びます 。<br></li>



<li>手順2で生成されたoffsets.txtに記載されている秒数（例：245.130）を入力し、OKを押します 。<br></li>



<li>正しい時間にシフトされた _timeshifted.vtt というファイルが新しく作成されます 。<br></li>
</ul>



<h4 class="wp-block-heading"><strong>5. VTTファイルの結合（手動）</strong></h4>



<p>それぞれの時間軸が整ったら、1つのファイルにまとめます。</p>



<ul class="wp-block-list">
<li>結合用の空ファイル（binded.vtt(※1)）を用意します 。<br></li>



<li>01.vttの中身をそのままペーストします 。<br></li>



<li>続けて、02_timeshifted.vtt、03_timeshifted.vtt の連番以降のテキスト部分を順番にコピーして下に追加し、保存します 。<br></li>
</ul>



<p>※1:あとで気付きました。bindedは間違った英語です。boundあるいはconbinedというのが適切です。</p>



<h4 class="wp-block-heading"><strong><strong><strong>6. 連番の振り直しと整理（クイックアクション）</strong></strong></strong></h4>



<p>結合したファイルは、字幕の通し番号（連番）が「1」から始まる箇所が複数混在してしまっています 。これを綺麗に整えます。</p>



<ul class="wp-block-list">
<li>binded.vtt を右クリックし、クイックアクションから「字幕VTTの連番を付け直す」を選択します 。<br></li>



<li>これにより、最初から最後まで番号が正しく振り直された完成版 renumbered.vtt が出来上がります 。<br></li>
</ul>



<h3 class="wp-block-heading">まとめ</h3>



<p>言葉遣いやテキストの微修正は、このように全体の形が綺麗に整った最後に行うのがおすすめです 。</p>



<p>地味にコツコツと進める手作業の部分もありますが、仕組みが非常に分かりやすいため、作業中のストレスはほとんど感じません 。<strong>Gem(ChatGPTもそう)の文字起こし精度が抜群に高いのは、単なる音声からの文字起こしだけでなく、動画内の視覚情報（映像）例えば、動画に登場する文字、人物の動きなどを認識するという、マルチモーダル処理を行っているため</strong>です。26年3月現在、CapCut、Vrew、Premiere Pro、Davinci Resolve、Filmoraの文字起こしは「映像情報」を加味せず、純粋に「音声データ」のみに依存しています。おかげで、Gemの場合は、手直しが非常に少なくて済むのが最大のメリットです 。</p>



<p>以上</p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28762</post-id>	</item>
		<item>
		<title>【WordPress】Apple Windowsの字幕表示の設定について</title>
		<link>https://imakat.com/2024/10/02/23205/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Tue, 01 Oct 2024 21:44:00 +0000</pubDate>
				<category><![CDATA[字幕作成]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[スマホ]]></category>
		<category><![CDATA[字幕]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPad]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=23205</guid>

					<description><![CDATA[字幕の作成に関する問題ですが、それは、規格が統一されていないことに尽きる、と言っていいです。動画を作成する人は、それに振り回されています。 その字幕作成の悩みの一つが、スマホなどの小さな画面を使って、解説の動画を視聴して [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      gap: 12px; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px;
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  /* ★変更：ダウンロードボタンの基本サイズを小さくし、文字の折り返しを防止 */
  .sc-dynamic-embed .dl-btn a {
    font-size: 12px !important;
    color: #d9534f;
    font-weight: bold;
    text-decoration: none;
    background: #fdf0ef;
    padding: 4px 6px;
    border-radius: 4px;
    border: 1px solid #d9534f;
    white-space: nowrap; 
  }
  .sc-dynamic-embed .dl-btn a:hover { background: #d9534f; color: #fff; }

  /* ★追加：スマホ画面（幅500px以下）の時は、さらに全体を縮小して1行に収める */
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link-container { gap: 6px; }
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
    .sc-dynamic-embed .dl-btn a { font-size: 11px !important; padding: 3px 5px; }
  }

  /* 行梱包時の基本スタイル */
  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  /* 古い枠内字幕ボックスを強制消去 */
  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=33" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
    <p class="sc-link dl-btn">
      <a href="#" id="imk-dynamic-dl-btn" target="_blank" rel="noopener" download style="display: none;">
        📥 動画をダウンロード
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=gTxuADx9.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=GUIDgaF4.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=j0ry31nq.vtt" label="日本語" srclang="ja" kind="subtitles" default></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>)  Apple Windowsの字幕表示の設定について<br>
(<a href="#" class="imk-cue" data-seek="0:10" translate="no">00:00:10</a>)  (1) Macの字幕設定方法　<br>
(<a href="#" class="imk-cue" data-seek="0:20" translate="no">00:00:20</a>)  まず最初に、WordPressブログを視聴する方への共通の対策です。<br>
(<a href="#" class="imk-cue" data-seek="0:26" translate="no">00:00:26</a>)  WordPressのカスタマイズ->追加CSSを開きます。<br>
(<a href="#" class="imk-cue" data-seek="0:30" translate="no">00:00:30</a>)  ご覧の部分のCSSを追加します。<br>
(<a href="#" class="imk-cue" data-seek="0:34" translate="no">00:00:34</a>)  このコードはブログへ添付します。字幕の背景を黒にする。字幕の背景の透過を50%にする。字幕の文字色を白にする。文字に少々影を追加する。以上4点です。<br>
(<a href="#" class="imk-cue" data-seek="0:44" translate="no">00:00:44</a>)  ここから各デバイスへの設定になります。設定は、各デバイスの「アクセシビリティ」へ行います。<br>
(<a href="#" class="imk-cue" data-seek="0:51" translate="no">00:00:51</a>)  最初はMacからです。「システム設定」->「アクセシビリティ」->「字幕」<br>
(<a href="#" class="imk-cue" data-seek="0:58" translate="no">00:00:58</a>)  先頭にある「透明な背景」を選択すると、上段にイメージが表示されます。これでいいので、このままにします。<br>
(<a href="#" class="imk-cue" data-seek="1:16" translate="no">00:01:16</a>)  MacでWordPressプレーヤーを再生します。<br>
(<a href="#" class="imk-cue" data-seek="1:28" translate="no">00:01:28</a>)  背景黒で透明度50%ですが、これが読みやすく、かつ下地も、まずまず見えます。<br>
(<a href="#" class="imk-cue" data-seek="1:41" translate="no">00:01:41</a>)  Macは以上です。<br>
(<a href="#" class="imk-cue" data-seek="1:51" translate="no">00:01:51</a>)  (2)Windowsの字幕設定方法　<br>
(<a href="#" class="imk-cue" data-seek="2:01" translate="no">00:02:01</a>)  Windowsは、「設定」->「アクセシビリティ」->「字幕」->「字幕のスタイル」と入ります。<br>
(<a href="#" class="imk-cue" data-seek="2:10" translate="no">00:02:10</a>)  Windowsは、「ビデオの設定を優先」するか否かの選択がありませんが、要するに、ここで指定した項目は上書きされます。<br>
(<a href="#" class="imk-cue" data-seek="2:17" translate="no">00:02:17</a>)  「テキスト」は白で不透明度100%、サイズは中、フォントはプロポーショナルゴシック。<br>
(<a href="#" class="imk-cue" data-seek="2:26" translate="no">00:02:26</a>)  「背景」は黒で不透明度75%<br>
(<a href="#" class="imk-cue" data-seek="2:33" translate="no">00:02:33</a>)  問題は、50%がないのですね。これだと、透けて見えないのではないかと思います。まあ仕方ないです。<br>
(<a href="#" class="imk-cue" data-seek="2:51" translate="no">00:02:51</a>)  WindowsでWordPressプレーヤーを再生します。<br>
(<a href="#" class="imk-cue" data-seek="3:05" translate="no">00:03:05</a>)  色々いじってみましたが、これが一番まともです。<br>
(<a href="#" class="imk-cue" data-seek="3:20" translate="no">00:03:20</a>)  以上がWindowsの設定です。<br>
(<a href="#" class="imk-cue" data-seek="3:31" translate="no">00:03:31</a>)  (3)iPadの字幕設定方法　<br>
(<a href="#" class="imk-cue" data-seek="3:42" translate="no">00:03:42</a>)  iPadは、「設定」->「アクセシビリティ」　->「標準字幕とバリアフリー字幕」<br>
(<a href="#" class="imk-cue" data-seek="3:51" translate="no">00:03:51</a>)  iPadは、「スタイル」で、一番上の「透明な背景」を選びます。上のイメージでは文字が小さく感じますが、実際は適当な大きさになっています。<br>
(<a href="#" class="imk-cue" data-seek="4:09" translate="no">00:04:09</a>)  iPadで、WordPressプレーヤーを再生します。<br>
(<a href="#" class="imk-cue" data-seek="4:20" translate="no">00:04:20</a>)  Macとほぼ同じ表示レベルです。読みやすく問題ないです。<br>
(<a href="#" class="imk-cue" data-seek="4:31" translate="no">00:04:31</a>)  iPadの設定は以上です。<br>
(<a href="#" class="imk-cue" data-seek="4:41" translate="no">00:04:41</a>)  (4) iPhoneの字幕設定方法　<br>
(<a href="#" class="imk-cue" data-seek="4:50" translate="no">00:04:50</a>)  (4-1) 枠内字幕と枠外字幕の比較<br>
(<a href="#" class="imk-cue" data-seek="4:58" translate="no">00:04:58</a>)  左側は、字幕を枠の外に表示して、右側は字幕を枠の中に表示しています。<br>
(<a href="#" class="imk-cue" data-seek="5:08" translate="no">00:05:08</a>)  枠外表示は、スマホなどの画面が小さい時、有効だと思います。<br>
(<a href="#" class="imk-cue" data-seek="5:21" translate="no">00:05:21</a>)  枠内表示は、文字が邪魔になるので、文字の背景を透過させる設定が求められます。<br>
(<a href="#" class="imk-cue" data-seek="5:37" translate="no">00:05:37</a>)  (4-2)字幕の背景の透明度を上げる設定<br>
(<a href="#" class="imk-cue" data-seek="5:46" translate="no">00:05:46</a>)  「設定」->「アクセシビリティ」　<br>
(<a href="#" class="imk-cue" data-seek="5:59" translate="no">00:05:59</a>)  「標準字幕とバリアフリー字幕」<br>
(<a href="#" class="imk-cue" data-seek="6:07" translate="no">00:06:07</a>)  「スタイル」->「新規スタイルを作成」を選択すると「スタイル1」ができます。<br>
(<a href="#" class="imk-cue" data-seek="6:14" translate="no">00:06:14</a>)  「スタイル1」を選択した状態で、右上の「編集」をクリックします。<br>
(<a href="#" class="imk-cue" data-seek="6:21" translate="no">00:06:21</a>)  「フォント」->「システムフォント(モノ)」->「ビデオの設定を優先」をオフ   ※オンにすると何故か明朝体になります。<br>
(<a href="#" class="imk-cue" data-seek="6:36" translate="no">00:06:36</a>)  「サイズ」->「大」を選択。 スマホは画面が小さいので、読もうと思うなら「大」がベターです。<br>
(<a href="#" class="imk-cue" data-seek="6:44" translate="no">00:06:44</a>)  文字の「カラー」->「ホワイト（デフォルト）」を選択。<br>
(<a href="#" class="imk-cue" data-seek="6:50" translate="no">00:06:50</a>)  背景の「カラー」->「ブラック（デフォルト）」->「ビデオの設定を優先」をオフ<br>
(<a href="#" class="imk-cue" data-seek="7:09" translate="no">00:07:09</a>)   背景の「不透明度」->「50%（デフォルト）」->「ビデオの設定を優先」をオフ<br>
(<a href="#" class="imk-cue" data-seek="7:21" translate="no">00:07:21</a>)   テキストの「不透明度」->「不透明（デフォルト）」<br>
(<a href="#" class="imk-cue" data-seek="7:37" translate="no">00:07:37</a>)   以上で、iPhoneの字幕の設定は終了です。<br>
(<a href="#" class="imk-cue" data-seek="7:46" translate="no">00:07:46</a>)  (5) VimeoやYouTubeの字幕の設定は、マニュアル操作。<br>
(<a href="#" class="imk-cue" data-seek="7:55" translate="no">00:07:55</a>)  Vimeoを例に、字幕を表示します。<br>
(<a href="#" class="imk-cue" data-seek="8:03" translate="no">00:08:03</a>)  デフォルトでは、黒の背景に白の文字で、透過度ゼロです。<br>
(<a href="#" class="imk-cue" data-seek="8:09" translate="no">00:08:09</a>)  どうすればいいか、ウロウロしています。<br>
(<a href="#" class="imk-cue" data-seek="8:16" translate="no">00:08:16</a>)  まあ、真っ黒も、悪くはないけど。<br>
(<a href="#" class="imk-cue" data-seek="8:26" translate="no">00:08:26</a>)  「CC」のボタンをクリック->「カスタマイズ」->「背景」<br>
(<a href="#" class="imk-cue" data-seek="8:34" translate="no">00:08:34</a>)  不透明度50%にします。<br>
(<a href="#" class="imk-cue" data-seek="8:52" translate="no">00:08:52</a>)  これなら、まあ、見やすいです。<br>
(<a href="#" class="imk-cue" data-seek="9:06" translate="no">00:09:06</a>)  それで問題は、ここで、このURLを再起動してみます。<br>
(<a href="#" class="imk-cue" data-seek="9:19" translate="no">00:09:19</a>)  再起動されました。<br>
(<a href="#" class="imk-cue" data-seek="9:27" translate="no">00:09:27</a>)  すると、元の、真っ黒に戻ってしまうということです。<br>
(<a href="#" class="imk-cue" data-seek="9:35" translate="no">00:09:35</a>)  Vimeoの字幕のカスタマイズは、毎回、マニュアル操作です。以上です。<br>
(<a href="#" class="imk-cue" data-seek="9:42" translate="no">00:09:42</a>)  この動画は以上です。ご視聴ありがとうございました。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    /* -----------------------------------------------
       1. ダウンロードボタンの自動セットアップ機能
       ----------------------------------------------- */
    function setupDownloadButton() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video');
      var dlBtn = target.querySelector('#imk-dynamic-dl-btn');

      if (video && dlBtn && dlBtn.style.display === 'none') {
        var src = video.currentSrc || video.src;
        if (!src) {
          var source = video.querySelector('source');
          if (source) src = source.src;
        }
        if (src) {
          dlBtn.href = src;
          dlBtn.style.display = 'inline-block';
        }
      }
    }

    /* -----------------------------------------------
       2. 字幕制御＆ハイライト機能（iPhone全画面 完全対応版）
       ----------------------------------------------- */
    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video');
      var listContainer = target.querySelector('details > p');
      
      if (!video || !listContainer) return false; 

      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = "hidden";
             }
          }
        }
      } catch(e){}

      video.addEventListener("webkitbeginfullscreen", function() {
          try {
              if(video.textTracks && video.textTracks.length > 0) {
                  for(var i=0; i<video.textTracks.length; i++){
                      if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') video.textTracks[i].mode = "showing";
                  }
              }
          } catch(e){}
      });
      video.addEventListener("webkitendfullscreen", function() {
          try {
              if(video.textTracks && video.textTracks.length > 0) {
                  for(var i=0; i<video.textTracks.length; i++){
                      if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') video.textTracks[i].mode = "hidden";
                  }
              }
          } catch(e){}
      });

      var detailsEl = target.querySelector("details");
      if (detailsEl) {
          detailsEl.open = true; 
          var summaryEl = detailsEl.querySelector("summary");
          if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
      }

      if (!listContainer.dataset.formatted) {
          var html = listContainer.innerHTML;
          var lines = html.split(/<br\s*\/?>/i);
          var newHtml = "";
          for(var j=0; j<lines.length; j++) {
              if(lines[j].trim() === "") continue;
              newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
          }
          listContainer.innerHTML = newHtml;
          listContainer.dataset.formatted = "true";
      }

      function parseTs(ts){
        if(!ts) return null;
        var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
        if(p.length===2) return p[0]*60 + p[1];
        if(p.length===3) return p[0]*3600 + p[1]*60 + p[2];
        return null;
      }

      var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
      if (rootSublist) {
        rootSublist.addEventListener("click", function(e){
          var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
          if(!a) return;
          e.preventDefault();
          var sec = parseTs(a.getAttribute("data-seek"));
          if(sec==null) return;
          try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
        });
      }

      video.addEventListener("timeupdate", function(){
        var desiredMode = isSpecialMode() ? "showing" : "hidden";
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var t = parseTs(cues[i].getAttribute("data-seek"));
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    /* -----------------------------------------------
       監視タイマー（URL抜き出し＆ボタン表示を継続的に実行）
       ----------------------------------------------- */
    var checks = 0;
    var checkTimer = setInterval(function(){
      setupDownloadButton();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    /* -----------------------------------------------
       3. 画面遷移時の停止機能
       ----------------------------------------------- */
    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<p>字幕の作成に関する問題ですが、それは、規格が統一されていないことに尽きる、と言っていいです。動画を作成する人は、それに振り回されています。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=xhUgzybc.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=xhUgzybc.png" alt="" style="width:125px;height:auto"/></a></figure>



<p>その字幕作成の悩みの一つが、スマホなどの小さな画面を使って、解説の動画を視聴してもらおうとすると、字幕が邪魔になることです。その解決策として、既に、<a href="https://imakat.com/2024/03/23/20191/" target="_blank">字幕を動画枠の外に表示する方法</a>は紹介してきましたが、この動画では、字幕の背景を透過させる設定方法を紹介しています。</p>



<p>なお、WordPressプレーヤーを使用する場合は、以下の方法で、デフォルトで透過率を設定することができます。</p>



<pre class="wp-block-code"><code>video::cue {
  background-color: rgba(0, 0, 0, 0.5); /* 背景を黒で透過率50% */
  color: white; /* 字幕の文字色を白に設定 */
  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); /* 文字に影を追加 */
}</code></pre>



<p>上のコードを、WordPressのカスタマイズ-&gt;追加CSS、へ追記して、公開のボタンを押します。</p>



<p></p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=Auj9lJJd.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=Auj9lJJd.png" alt=""/></a></figure>



<p>以上</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">23205</post-id>	</item>
	</channel>
</rss>
