<?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>Mac | imakat.com</title>
	<atom:link href="https://imakat.com/tag/mac/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Tue, 10 Mar 2026 06:28:10 +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>Mac | 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>第３章：YouTubeなど（大手）に依存しないで配信する～複数の再生サーバーを切り替える仕組み～</title>
		<link>https://imakat.com/2025/04/25/25930/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 24 Apr 2025 20:19:59 +0000</pubDate>
				<category><![CDATA[マイライブラリ]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[識別子]]></category>
		<category><![CDATA[ストリーミング]]></category>
		<category><![CDATA[直リンク]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[トークンリンク]]></category>
		<category><![CDATA[Dropbox]]></category>
		<category><![CDATA[Webホスティング]]></category>
		<category><![CDATA[メディアアセット]]></category>
		<category><![CDATA[NFC]]></category>
		<category><![CDATA[RFC]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=25930</guid>

					<description><![CDATA[メディアライブラリを作ろう 本章では、YouTubeやTikTokなどの大手拡散型プラットフォームを使用せず、自前の仕組みで動画やメディアを配信する方法について深掘りしていきます。つまり、クラウド時代の“ハンドメイド配信 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>メディアライブラリを作ろう</p>



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



<p>本章では、YouTubeやTikTokなどの大手拡散型プラットフォームを使用せず、自前の仕組みで動画やメディアを配信する方法について深掘りしていきます。つまり、クラウド時代の“ハンドメイド配信”を実現するための枠組みです。</p>



<h3 class="wp-block-heading"><strong>1. 特定の大手に依存しないということの意味</strong></h3>



<p>YouTubeなどの大手は、確かに拡散力や安定性に優れていますが、同時にそのプラットフォームの規約や方針変更に大きく左右されます。広告挿入やアルゴリズムによる露出制限など、制作者の意思とは無関係な制限が突然加わる可能性も否定できません。それからYouTubeやTikTokなど大手の多くは、少し手を加えるだけで簡単に他人の動画を切り抜いて転用できる、AI自動生成物がその真偽を検証されることなく配信される、そうした緩さがあるため、どうしても信用性は低く、オモチャや娯楽の道具として一段低く扱われやすいことがあります。</p>



<p>私が目指すのは、小規模ながらも自由度が高く、そして制作者の意思で完結できる配信手段です。ただし、ここには大きな課題もあります。それは“<strong>小さな仕組みほど不安定で消えやすい。小さな会社ほど資金が乏しくすぐ倒産する。</strong>”という現実です。</p>



<p>この課題は、製造業におけるサプライチェーンの問題と非常によく似ています。特定の国や工場に依存しすぎると、何らかの外的要因で供給が止まるリスクがあります。そうでないにしても関税のように異常な高コストになるリスクがあります。同様に、配信インフラが一箇所に依存していると、そのサービスが終了した瞬間にすべての再生が止まってしまいます。</p>



<p>だからこそ必要なのが「<strong>複数の小規模の再生サーバーを柔軟に切り替える仕組み</strong>」です。</p>



<h3 class="wp-block-heading"><strong>2. 再生URLの設計と意味</strong></h3>



<p>私が使っている再生URLの構造は以下の通りです：</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td><strong>https://imakat.com/rd.php?id=Abcd0123.png</strong></td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li>imakat.com は私の管理しているドメイン名です。</li>



<li>rd.php は再生用の振り分けスクリプトです。</li>



<li>Abcd0123.png の部分が、一意の識別子になっています。</li>
</ul>



<p>この識別子には<strong>ランダムな8文字の大小英文字数字</strong>を使い、あえて<strong>拡張子（.png や .mp4 など）を付けた形式</strong>を採用しています。<br>これにより、URLだけを見てもおおよそのファイル種別が判断できるため、運用や整理の際にとても便利です。</p>



<p>よく見かける「拡張子なしのランダム識別子」も確かにセキュリティ的な利点はありますが、その一方でファイル内容の把握や管理は困難になります。</p>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/173W_0PrUWcWEpCzcjsJebm-cUwZxX73yCvw54q_GTH4/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vSWXRozx45bwD3f3QE5AU3vUMkMPglNP1MeGljlgAUpJlZp_B4sgespmr6u5SEJH92lk39aL15h7zT8/pub?w=960&#038;h=720"
></a>



<p>WordPressサーバー側で、phpスクリプトによって、選択された再生サーバー番号に合わせて、送り込んだJSONファイルとの照合を行ったりエンコード後のURLを生成するなどの作業を行っています。</p>



<h4 class="wp-block-heading">直リンク方式の場合は、ファイルパスのエンコードが必要</h4>



<p>直リンク方式(ファイルパス方式)の場合に、ファイルパスのエンコードが必要になりますが、ややこしい問題は、そのエンコードの方式が、サーバー会社によって異なる点です。各社が提供したエンコード後URLと、自分がファイルパスに基づく直リンクをエンコードしたURL、両者を比較して、それが一致するエンコード方式を使用することです。一致しないと、「ファイルが見つかりません」となり再生されません。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>mmediaまたはpmedia以下のファイルパス</td><td>/mmedia/id45_メディアライブラリ_はじめに/250411_メディアライブラリ_はじめに.mp4</td></tr><tr><td><strong>TypeA</strong><br>[NFC.RFC3986 URL encoding]方式によるエンコードをすると&#x27a1;&#xfe0f;</td><td>/mmedia/id45_%E3%83%A1%E3%83%86%E3%82%99%E3%82%A3%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%95%E3%82%99%E3%83%A9%E3%83%AA_%E3%81%AF%E3%81%97%E3%82%99%E3%82%81%E3%81%AB/250411_%E3%83%A1%E3%83%86%E3%82%99%E3%82%A3%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%95%E3%82%99%E3%83%A9%E3%83%AA_%E3%81%AF%E3%81%97%E3%82%99%E3%82%81%E3%81%AB.mp4</td></tr><tr><td><strong>TypeB</strong><br>[NFC,部分エンコード(ブラウザ互換型)&nbsp;]によるエンコードをすると&#x27a1;&#xfe0f;</td><td>/mmedia/id45_%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA_%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB/250411_%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA_%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB.mp4</td></tr><tr><td></td><td>&#x2b06;&#xfe0f;<strong>TypeAとTypeBとでは、よく見ると、あちこち、かなり文字が異なっています。</strong></td></tr></tbody></table></figure>



<p><br>この問題を除けば、直リンク方式の方が、今回行っているような構築は、はるかに簡単に済みます。<br>ただし現実には、直リンク方式を提供するクラウドストレージの会社は非常に少なくなり、pCloudはそのうちの1社です。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td colspan="2">WordPress(Xserver)内のURL再生が可能な状態にする(rd.php、再生用振り分けスクリプト)</td></tr><tr><td colspan="2"><a href="https://imakat.com/?pubtxt=マイライブラリXserverのrdphp_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></tbody></table></figure>



<p>結局、そのクラウドストレージがその内部にWebサーバーを建てること(Webホスティング)を許可しているかどうか、Webサーバーを建てることができれば、直リンク方式の開放ができる可能性が高いです。次章で深掘りしますが、残念ながら、例えば、Dropbox、Googleドライブ、iCloudドライブ、Oneドライブなど主要大手は、ストレージの中にWebサーバーを建てることができなくなっているわけです。その中で、Dropboxはraw=1により表示が可能、pCloudはパブリックフォルダにより表示が可能、と珍しい存在になっているわけです。</p>



<p>ただし、直リンク方式は、ファイルパスやファイル名を変更するとリンク切れを起こす、という致命的欠点があります。この欠点の克服方法を、別の章で紹介することにします。</p>



<h3 class="wp-block-heading"><strong>3. リンク提供とストリーミング再生の違い</strong></h3>



<p>再生URLは、<strong>動画や音声などのストリーミング再生、画像再生</strong>を行うための仕組みですが、<strong>ファイルの直接ダウンロードリンク</strong>としても応用可能です。たとえばExcelファイルの配布などにも対応できます。</p>



<p>ただし、<strong>再生</strong><strong>URL</strong><strong>をダウンロード専用の仕組みとして多用するのはおすすめしません</strong>。本来の目的はストリーミングにあるため、無理に使い方を広げすぎると運用が複雑になってしまいます。</p>



<h3 class="wp-block-heading"><strong>4. </strong>再生までの処理フロー</h3>



<p>以下が再生までの処理フローです：</p>



<ol class="wp-block-list">
<li>ユーザーがブラウザやメールクライアントなどから再生URLにアクセスする</li>



<li>rd.php が呼び出され、該当する識別子（例：Abcd0123.png）に紐づくサーバーを判定する</li>



<li>メディアライブラリアプリ(AppSheet)にて選ばれた再生サーバー（Dropbox、Xserver、pCloudなど）へ転送される</li>



<li>ストリーミング再生が開始される</li>
</ol>



<p>これにより、<strong>複数の配信先を動的に切り替えられる柔軟な配信構造</strong>が実現します。たとえ1つのサーバーに不具合が起きても、他のサーバーで代替再生が可能になります。</p>



<h3 class="wp-block-heading">次回予告：</h3>



<p><strong>第４章では、「リンク切れを防ぐ仕組みほか」</strong>についてご紹介します。<br></p>



<p>&#x27a1; <a href="https://imakat.com/2025/04/26/25984/" target="_blank">第４章を読む</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-center"><a href="https://imakat.com/media_library1" target="_blank">&#x1f517; 目次ページへ戻る</a></p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">25930</post-id>	</item>
		<item>
		<title>第2章「メディアライブラリへの登録〜パイプライン処理〜」</title>
		<link>https://imakat.com/2025/04/08/25796/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Tue, 08 Apr 2025 02:02:58 +0000</pubDate>
				<category><![CDATA[マイライブラリ]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[メディアアセット]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Dropbox]]></category>
		<category><![CDATA[MAM]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=25796</guid>

					<description><![CDATA[メディアライブラリを作ろう ポイント解説： 作成するスクリプトは、結構、分量があります。ChatGPTを使い、ゆっくり進めるのがいいです。以下のスクリプトをChatGPTへコピペして、（１）「このスクリプトの解説をしてく [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>メディアライブラリを作ろう</p>


<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=46" 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; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" poster="https://imakat.com/rd.php?id=kmelubbx.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=p5ZFXLqv.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=enPvHIg9.vtt" label="日本語" srclang="ja" kind="subtitles"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><div class="dr5emd-sublist"><details><summary>字幕一覧(クリック)</summary> <p>
(<a href="#" class="imk-cue" data-seek="0:00">00:00:00</a>)  〜メディアライブラリを作ろう〜<br>
(<a href="#" class="imk-cue" data-seek="0:18">00:00:18</a>)  メディア用ライブラリですね。そのパイプライン処理をですね。やってみたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="0:30">00:00:30</a>)  まずこの画面にですね。画像が入っているフォルダーがあります。<br>
(<a href="#" class="imk-cue" data-seek="0:37">00:00:37</a>)  1つこれはChatGPTで作った画像ですけれどもこの画像ですね。pmediaフォルダにコピーします。<br>
(<a href="#" class="imk-cue" data-seek="0:54">00:00:54</a>)  実はもうコピーしてあります。このように「鳥の群れ」のですね。写真が入ってます。<br>
(<a href="#" class="imk-cue" data-seek="1:05">00:01:05</a>)  次にこのファイルの上でメディアライブラリ作成を行います。<br>
(<a href="#" class="imk-cue" data-seek="1:12">00:01:12</a>)  データがPythonによってGASへ送られます。<br>
(<a href="#" class="imk-cue" data-seek="1:24">00:01:24</a>)  ちょっと待つのですがGASへ送られました。GASにデータが正常に送信されました。<br>
(<a href="#" class="imk-cue" data-seek="1:37">00:01:37</a>)  OKを押します。<br>
(<a href="#" class="imk-cue" data-seek="1:40">00:01:40</a>)  この状態ですとどうなってるかと言うとSpreadsheetを持ってきます。<br>
(<a href="#" class="imk-cue" data-seek="1:50">00:01:50</a>)  そうするとですね。Spreadsheetの1番上段にですね。もう、ChatGPT今のファイルですね。それが登録されてます。<br>
(<a href="#" class="imk-cue" data-seek="2:06">00:02:06</a>)  同時にこれに登録されていれば当然なんですが、<br>
(<a href="#" class="imk-cue" data-seek="2:14">00:02:14</a>)  メディアライブラリですね。<br>
(<a href="#" class="imk-cue" data-seek="2:16">00:02:16</a>)  AppSheetで作ったメディア用ライブラリの先頭にもですね。ChatGPTの画像が入ってきます。<br>
(<a href="#" class="imk-cue" data-seek="2:34">00:02:34</a>)  これ今現在、処理が少し時間がかかるので、<br>
(<a href="#" class="imk-cue" data-seek="2:43">00:02:43</a>)  「エラー：指定されたIDのデータが見つかりません」となりますが、少し待ちます。<br>
(<a href="#" class="imk-cue" data-seek="2:51">00:02:51</a>)  どうでしょうか。はい再生URLから「鳥の群れ」の画像が表示されました。<br>
(<a href="#" class="imk-cue" data-seek="3:04">00:03:04</a>)  これは実はいくつかの再生サーバーに置いてあるんですけれども、<br>
(<a href="#" class="imk-cue" data-seek="3:11">00:03:11</a>)  Dropboxリンクからはこのように再生されます。<br>
(<a href="#" class="imk-cue" data-seek="3:18">00:03:18</a>)  それからもう一つWPエンコード後URL、これはWordPressサーバーですが、そこからもしっかり再生されます。<br>
(<a href="#" class="imk-cue" data-seek="3:32">00:03:32</a>)  いくつか再生サーバーがあるんですけれども、それを選択をするようになってまして、<br>
(<a href="#" class="imk-cue" data-seek="3:38">00:03:38</a>)  選択番号3っていうのはですね。このWordPressサーバーから引っ張ってくることになっています。<br>
(<a href="#" class="imk-cue" data-seek="3:50">00:03:50</a>)  これですね。この再生URLこれをクリックするとWordPressサーバーから引っ張ってくるようになっています。今3番を選んでますからですね。<br>
(<a href="#" class="imk-cue" data-seek="4:07">00:04:07</a>)  このような形で処理が行われます。　<br>
(<a href="#" class="imk-cue" data-seek="4:14">00:04:14</a>)  それでは次ですね。もう一つの改良点についてですね。説明します。<br>
(<a href="#" class="imk-cue" data-seek="4:22">00:04:22</a>)  今の1つのファイルを登録したわけですね。<br>
(<a href="#" class="imk-cue" data-seek="4:28">00:04:28</a>)  このChatGPTimage..pngを登録したわけですけれども、<br>
(<a href="#" class="imk-cue" data-seek="4:34">00:04:34</a>)  このChatGPTimage..と言う抽象的な名前ですと、何のことかわからんわけですね。<br>
(<a href="#" class="imk-cue" data-seek="4:42">00:04:42</a>)  それでファイル名の中に具体的な例えば何の映像だとかそういうことをですね。書いておいたほうがいいですよね。<br>
(<a href="#" class="imk-cue" data-seek="4:54">00:04:54</a>)  ファイルの名前を変えるわけです。その場合。<br>
(<a href="#" class="imk-cue" data-seek="5:00">00:05:00</a>)  名前を変えます。<br>
(<a href="#" class="imk-cue" data-seek="5:07">00:05:07</a>)  具体的には日付、これはですね。これは「鳥の群れ」とします。名前を変えました。<br>
(<a href="#" class="imk-cue" data-seek="5:33">00:05:33</a>)  そうするとですね。中で自動処理が進んでまして、<br>
(<a href="#" class="imk-cue" data-seek="5:41">00:05:41</a>)  名前を変更する前のファイルパスそれから名前を変更した後のファイルパスをデータとして保存してます。従ってそれで置き換えができるようになってます。<br>
(<a href="#" class="imk-cue" data-seek="5:56">00:05:56</a>)  例えば今、ここにあるファイルですけどもしばらく放置しておきます。<br>
(<a href="#" class="imk-cue" data-seek="6:09">00:06:09</a>)  実際、5分に1回の処理なんですが、ちょっと5分待つことにはなるんですが、<br>
(<a href="#" class="imk-cue" data-seek="6:17">00:06:17</a>)  何もしなくていいです<br>
(<a href="#" class="imk-cue" data-seek="6:20">00:06:20</a>)  そうするとここがですね変わってきますので、少々お待ちください。<br>
(<a href="#" class="imk-cue" data-seek="6:31">00:06:31</a>)  名前が変わりました「鳥の群れ」ですね。名前が変わってます。<br>
(<a href="#" class="imk-cue" data-seek="6:40">00:06:40</a>)  名前は変わりましたが再生URLの番号ですね。識別番号は変わってません。<br>
(<a href="#" class="imk-cue" data-seek="6:50">00:06:50</a>)  従って、実際このURLを使ってWordPressに記述したとしてもですね。全然それは変更しなくてもいいわけですね。<br>
(<a href="#" class="imk-cue" data-seek="7:05">00:07:05</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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

  <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>



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



<p>作成するスクリプトは、結構、分量があります。ChatGPTを使い、ゆっくり進めるのがいいです。以下のスクリプトをChatGPTへコピペして、（１）「このスクリプトの解説をしてください」と、まず解説をしてもらう（２）その解説の中で、自分向けに修正する箇所を指摘して、スクリプトの記述を指示する、そのようなやり方が効率的です。表の右欄に、スクリプトをリンクします。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td colspan="2" style="background-color:#dddddd"><strong>パイプライン処理</strong>(画面入力をトリガーに、一品料理で一連の処理を行う)</td></tr><tr><td>&#x2b07;&#xfe0f;＜マイライブラリ画面入力＞<br>Finderで選択したファイルを処理し、対応するDropbox共有リンクを自動取得して送信スクリプトに渡すAppleScript。ファイルのパスや拡張子を取得し、日本語などを除去してDropbox形式のファイル名に整形。Python仮想環境のget_dropbox_link.pyでリンクを生成し、ファイル名の整合性を確認後、send_request.pyでリンク情報を送信。</td><td><a href="https://imakat.com/script_list/?pubtxt=マイライブラリ_画面入力_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>&#x2b07;&#xfe0f;＜マイライブラリDropboxAPI認証リンク取得GAS通信＞<br>DropboxのOAuth認証設定、リンク自動取得、GASとの通信を行う3本のPythonスクリプト群。<br>①dropbox_auth_setup.pyはローカルHTTPサーバで認証コードを受け取り、Dropboxのアクセストークンとリフレッシュトークンを取得する。<br>②get_dropbox_link.pyはリフレッシュトークンを用いてDropbox APIに接続し、指定ローカルファイルの共有リンクを取得または生成し、dl=0をraw=1に変換して出力する。<br>③send_request.pyはAppleScriptから受け取ったDropboxリンクやファイル情報をGASのエンドポイントへJSON形式で送信し、更新処理を実行する。</td><td><a href="https://imakat.com/script_list/?pubtxt=マイライブラリ_dropboxAPI_Mac_GASデータ交換_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>&#x2b07;&#xfe0f;<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1JgcOPS8GESxG34LDFSUE1i3CVe0PSM6sAyZrfqkV0cc/edit?usp=sharing">＜マイライブラリ生成更新処理＞<span class="fa fa-external-link external-icon anchor-icon"></span></a><br>mediaLibrary.gsは、Dropbox等のメディアファイル情報をF1シートで一元管理し、その変更を自動反映するGASです。ファイル名・パスから一意なwpidexを生成し、sb付き一時ファイル名や?v=付きURL、NFC差、連続スラッシュなどを正規化して突合します。doPostはmodeにより、ライブラリのフル再構築やvideoembed.jsonのみ更新、通常の作業行追加＋処理を切り替えます。processWorkingRecordはF3のパス変更履歴を反映しつつ、K=ADD行をADD2に更新し、JSON生成とライブラリ整理、pcloudidシートへの同期を行います。cleanMediaLibraryはDEL行や重複を除去し、更新日時で並べ替え、フラグをFALSEに戻します。videoembed関連は「動画パッケージ」シートから埋め込みHTMLを集約し、XserverのPHPにJSONをPOST送信します。</td><td><a href="https://imakat.com/script_list/?pubtxt=マイライブラリ_生成更新処理_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>&#x2b07;&#xfe0f;＜メディアおよびJSONをXserverへ更新＞<br>Dropbox → Xserver 同期用のメインスクリプトは、pmedia・mmedia・meta_gd_wp_data を Homebrew 版 rsync で転送し、SSH鍵を自動ロードして毎分同期するよう LaunchAgent から実行される。ログは /tmp と $HOME/scripts/logs に記録される。<br>しかし rsync が残留してフリーズすることがあるため、毎日 3:30 に自動復旧スクリプトが動作し、pmedia/mmedia 関連の rsync プロセスを検出して kill し、メインの LaunchAgent（com.xxxxxxxxm1.sync_dropbox_xserver_m1）を unload/load し直して正常状態へ戻す仕組みとなっている。</td><td><a href="https://imakat.com/script_list/?pubtxt=メディアおよびJSONをXserverへ更新および自動復帰_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>&#x2b07;&#xfe0f;＜配信サーバー切り替えリダイレクト処理＞<br>rd.phpは、指定されたidに対応するメディア情報をJSONから取得し、該当URLへ転送または中継出力するPHPスクリプト。txt・vtt・srtなど文字ファイルの場合は、文字化け防止のためサーバー側でUTF-8へ変換して直接配信する。Dropbox・Xserver・pCloudなど複数サーバーのURLを動的に切り替え、キャッシュ防止や診断表示（?diag=1）にも対応する。</td><td><a href="https://imakat.com/script_list/?pubtxt=マイライブラリXserverのrdphp_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></tbody></table></figure>



<p></p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td colspan="2" style="background-color:#dddddd"><strong>バックグラウンド処理</strong>(常時監視する)</td></tr><tr><td colspan="2">＜ファイルパス変更処理＞<br>mmedia・pmedia フォルダを常時監視し、ファイルやフォルダの移動・リネーム（MOVED）を検出して記録する Python スクリプト。検出時には変更前・変更後パス、JST の更新時刻、更新フラグ TRUE を Google スプレッドシート（sheet1）へ追記し、その後シート全体を読み込んで (A,B) が同じ重複記録は「最も古いものだけ残す」形に正規化し、更新日時の降順で再整列して書き戻す。scripts_pub や .dropbox など特定パスは無視するフィルタを搭載。watchdog によりディレクトリを監視し続け、ログは ~/Library/Logs に記録。LaunchAgent（com.xxxxxxxx.filewatcher.plist）を用いて macOS 起動時に自動実行される構成となっている。</td></tr><tr><td colspan="2"><a href="https://imakat.com/script_list/?pubtxt=ファイルパス変更処理_gasからpython移行_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></tbody></table></figure>



<p>上の処理はMacを使った処理ですが、ChatGPTの分析では、Windowsへの移植には、以下が変更点になります。Mac、Windowsで共通して使えるGAS、AppSheetを中心に据える作り方がベターと言えます。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td colspan="3"><strong>Windowsへの変更点</strong></td></tr><tr><td><strong>処理</strong></td><td><strong>Mac</strong></td><td><strong>Windoowsでの代替</strong></td></tr><tr><td>GUI自動処理</td><td>AppleScript</td><td>PowerShell or Python GUI</td></tr><tr><td>クリップボード</td><td><code>the clipboard</code></td><td><code>pyperclip</code>&nbsp;(Python)</td></tr><tr><td>パス処理</td><td>POSIXパス</td><td><code>os.path</code>&nbsp;(Python)</td></tr><tr><td>sed/basename</td><td>shellコマンド</td><td>Pythonの標準ライブラリ</td></tr><tr><td>GAS通信</td><td><code>requests.post</code></td><td>そのままOK</td></tr><tr><td>フォルダ監視</td><td>shell + find/comm</td><td>PowerShell +&nbsp;<code>Compare-Object</code></td></tr><tr><td>自動同期</td><td>rsync</td><td>robocopy / WinSCP</td></tr><tr><td>タスク自動実行</td><td>Automator or cron</td><td>Windowsタスクスケジューラ</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">次回予告：</h3>



<p><strong>第3章では、「<strong>YouTube（大手）に依存しないで配信する</strong>」</strong>についてご紹介します。<br></p>



<p>&#x27a1; <a href="https://imakat.com/2025/04/25/25930/" target="_blank">第3章を読む</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-center"><a href="https://imakat.com/media_library1" target="_blank">&#x1f517; 目次ページへ戻る</a></p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">25796</post-id>	</item>
		<item>
		<title>第1章「メディアライブラリ構築の目的と背景」</title>
		<link>https://imakat.com/2025/04/03/25693/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 03 Apr 2025 11:45:00 +0000</pubDate>
				<category><![CDATA[マイライブラリ]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Dropbox]]></category>
		<category><![CDATA[MAM]]></category>
		<category><![CDATA[メディアアセット]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=25693</guid>

					<description><![CDATA[メディアライブラリを作ろう はじめに： いまの時代、動画はたくさん出回っています。でも、その動画を作るために使った素材――たとえば写真や音声、字幕や説明文など――は、紐づいて保存されているでしょうか。 最近の動画編集ツー [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>メディアライブラリを作ろう</p>


<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=45" 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; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" poster="https://imakat.com/rd.php?id=SNebSNKN.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=b2WjRm31.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=06LGXJgR.vtt" label="日本語" srclang="ja" kind="subtitles"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><div class="dr5emd-sublist"><details><summary>字幕一覧(クリック)</summary> <p>
(<a href="#" class="imk-cue" data-seek="0:00">00:00:00</a>)  メディアライブラリを作ろう〜はじめに〜<br>
(<a href="#" class="imk-cue" data-seek="0:19">00:00:19</a>)  メディアライブラリを作ろうというテーマで、解説を始めます。どちらかというと、地味なテーマで、かっこよくも、美しくもないです。<br>
(<a href="#" class="imk-cue" data-seek="0:36">00:00:36</a>)  しかし、例えば、動画の配信は、ほとんどの方が、YouTubeやTikTokを使っていますね。<br>
(<a href="#" class="imk-cue" data-seek="0:48">00:00:48</a>)  やたら再生回数、いいね、登録を求められて、そういうやり方は、自分にとっては風呂敷を広げ過ぎです。 <br>
(<a href="#" class="imk-cue" data-seek="1:03">00:01:03</a>)  そんなことよりも、地味にITやパソコンをやってるマイナーな層に、配信できればそれでいいと思っています。<br>
(<a href="#" class="imk-cue" data-seek="1:16">00:01:16</a>)  だから、YouTubeを使わないで、自分のホームページ、Web、ブログから動画や画像を配信することができるようにしたいわけです。<br>
(<a href="#" class="imk-cue" data-seek="1:32">00:01:32</a>)  コマーシャルなど入らないように配信したいです。<br>
(<a href="#" class="imk-cue" data-seek="1:39">00:01:39</a>)  そう望まれる方は、このシリーズが役に立つのではと思います。<br>
(<a href="#" class="imk-cue" data-seek="1:45">00:01:45</a>)  私は、WordPressを使いますが、DNSが設定できてWeb配信ができれば、他のやり方でも、構造的には同じことかと思います。<br>
(<a href="#" class="imk-cue" data-seek="2:04">00:02:04</a>)  そういった普通の作業方法は、自分のパソコンで動画や画像の作成をして、それをレンタルサーバーへアップロードする、この流れが正しいです。<br>
(<a href="#" class="imk-cue" data-seek="2:20">00:02:20</a>)  ところで、動画や画像などはメディアアセットと呼びますが、メディアアセットは、最近はDropboxなどのクラウドストレージで作業をして保管をしていることも多くなっています。<br>
(<a href="#" class="imk-cue" data-seek="2:43">00:02:43</a>)  クラウドストレージは、そのままリンクを共有できるものが多く、それをブログに貼り付けて公開する方法も、一般化しています。<br>
(<a href="#" class="imk-cue" data-seek="2:57">00:02:57</a>)  ただし気掛かりな点は、クラウドストレージもレンタルサーバーも、いつ撤退するか分からない点です。<br>
(<a href="#" class="imk-cue" data-seek="3:09">00:03:09</a>)  その対処は、完璧な方法はありませんが、ひと所に依存しない、複数使えるようにしておくことだ、と考えます。<br>
(<a href="#" class="imk-cue" data-seek="3:25">00:03:25</a>)  今回のような、ハンドメイドの配信システムを持つメリットは、やはり、いつでも自由に手直しができることです。<br>
(<a href="#" class="imk-cue" data-seek="3:37">00:03:37</a>)  結局、趣味の内容をブログにするので、記事も動画画像も頻繁に手直ししますから。<br>
(<a href="#" class="imk-cue" data-seek="3:47">00:03:47</a>)  私の作ったものは、メディアライブラリと動画パッケージ、動画ライブラリですが、頻繁に手直しする人のための道具です。<br>
(<a href="#" class="imk-cue" data-seek="4:02">00:04:02</a>)  図を見ていただきたいですが、<br>
(<a href="#" class="imk-cue" data-seek="4:05">00:04:05</a>)  動画や画像といったメディアアセットは、中には大容量の、500MBを超えるようなものもあり、入れ物が必要になります。<br>
(<a href="#" class="imk-cue" data-seek="4:22">00:04:22</a>)  サーバーに保管します。<br>
(<a href="#" class="imk-cue" data-seek="4:28">00:04:28</a>)  しかし、そのメディアアセットをマネジメントする、管理するための情報は、私の場合、Googleドライブ内のSpreadsheetで行っています。<br>
(<a href="#" class="imk-cue" data-seek="4:44">00:04:44</a>)  アセット自体の管理と、運用するためのメタ情報の管理は、分離することができます。<br>
(<a href="#" class="imk-cue" data-seek="4:55">00:04:55</a>)  図書館の本の場合は、貸し出すためのサービスが、本を貸し出すための窓口が各図書館に必要になりますが、　<br>
(<a href="#" class="imk-cue" data-seek="5:08">00:05:08</a>)  動画や画像といったメディア情報は、その置き場所ごとに管理の仕組みを設ける必要はなくて、<br>
(<a href="#" class="imk-cue" data-seek="5:20">00:05:20</a>)  一括してまとめてコントロールすることができます。<br>
(<a href="#" class="imk-cue" data-seek="5:27">00:05:27</a>)  アセット自体の管理と、運用するためのメタ情報の管理は、分離することができます。<br>
(<a href="#" class="imk-cue" data-seek="5:39">00:05:39</a>)  ただし、メタ情報のメンテナンスは瞬時にできますが、アセットの移動は、何分かかかる場合もあります。そこにはどうしてもタイムラグが生じます。<br>
(<a href="#" class="imk-cue" data-seek="6:02">00:06:02</a>)  ブログは修正されたが、動画や画像がまだ届いていない、といったタイムラグもどうしても生じます。<br>
(<a href="#" class="imk-cue" data-seek="6:14">00:06:14</a>)  それでは、次は、実際に、Macの画面操作を見ていきます。<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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

  <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>



<h3 class="wp-block-heading">はじめに：</h3>



<p>いまの時代、動画はたくさん出回っています。<br>でも、その動画を作るために使った素材――たとえば写真や音声、字幕や説明文など――は、紐づいて保存されているでしょうか。</p>



<p>最近の動画編集ツールは、ブラウザから手軽に使えるものが多くなっています。<br>素材をいくつかアップして、簡単な操作で動画が完成する。便利で楽しい仕組みになっています。<br>そして完成した動画は、そのままYouTube、TikTokなどの配信サイトにアップされ、世界中に届けられます。</p>



<h4 class="wp-block-heading">プロセスは、隠された箱の中</h4>



<p>時代は生成AIですね。</p>



<p>でも、その一方で、完成した動画は、「どうやって作られたのか」、「どんな素材で作られたか」は、作成者は全く分からない、原型を留めないほどに、変形させられるものも多々あります。こうなった時、それが私の作品、所有者は私、と言われても、すっと腑に落ちません。</p>



<p></p>



<h3 class="wp-block-heading">出発点は「整理整頓」：</h3>



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



<p>さて、これからの時代、動画などのメディアコンテンツの作り方は、どんな考え方に傾いていくでしょうか。</p>



<h4 class="wp-block-heading">適当なものを放り込んで、ボタンを押したらヒョッコリ出来ただけ</h4>



<p>ひとつは、「完成した動画があれば、素材がなにだったか、原型がどうだったかは、気にしない。レシピはアプリ会社が用意したものから選ぶだけでいい。」という考え方。早い安い美味い、インスタント即決重視。</p>



<p>もうひとつは、「動画の元になった素材や、その作り方の記録も残っていて、<strong>所有権は私のもの</strong>であり再加工も私はできる」という考え方。音楽制作や文芸で著作権の大切さを感じた人にある感覚でしょうか。</p>



<p>前者は、何が原因でどういう条件でこの結果となったかが分からないので、何を大事に残したらいいかが分からない。素材軽視、意外性重視、偶然好み、結果だけあればいい。完成物だけ持って飛び出していく人。やりっぱなしで、でも元ネタはここにあるはず、となると捨てられず、家はゴミ屋敷。</p>



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



<p>いいえ全員そうだとは言いませんが、概してそう。</p>



<p>小さい頃から言われ続けてきた整理整頓は、やはり重要です。</p>



<p>完成した動画だけでなく、それを作るまでに使った素材や字幕、説明なども、あとから見返せるようにしたい。<br>再利用や別の作品への展開にも役立ちます。</p>



<p></p>



<h3 class="wp-block-heading">「フォルダ整理」の次に「ライブラリ」生成へ：</h3>



<p>このシリーズでは、**「メディアライブラリ」**を、メディアコンテンツを作成保存するDropbox（私の場合)を出発点にして、身近な道具を活用しながら、どう作っていくか、これまで数回に渡り掲載してきたライブラリ生成のまとめとして、ご紹介していきます。</p>



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



<p>メディアライブラリとは、図書館がサービスとして本を貸し出してくれるように、そのメディアコンテンツを配信してくれるところです。しかし図書館といえど世の中のすべての書物を扱えるわけではありません。日本の図書館には、ほとんどが日本語の書物です。同じように、ここでいうメディアライブラリは、「自分が所有している配信可能なコンテンツのうち、配信する予定のあるものを、配信できる状態にスタンバイさせたもの」となります。</p>



<p>ここから先は、メディアコンテンツを流通させる手法を取り扱っていくので、メディアの中身そのものというより、メディアの属性やメタ情報に焦点を当てていきます。そしてメディアの総体をメディアアセットと呼んでいくことにします。<br><br>(※アセットとは、一般的には「資産」の意味です。「情報」に対して「情報資産」と呼ぶと、まあ意味は何となく分かりますが、しかしこの「情報資産」は、質量を持たず、瞬時に無限に複製移動出来る不思議な存在です。)</p>



<p>ですから、包含関係で言うと、「自分の所有するメディアアセット⊇配信可能なアセット⊇配信する予定のあるアセット⊇配信できる状態にスタンバイしたアセット」となります。</p>



<p>具体的に私の例で言うと、</p>



<p>(A)自分の所有するメディアアセット(様々なデバイス):<br>iPhoneやiPadに保存した画像やイラスト、動画、音声など、FinalCutPro、Cubase、図形描画、ドキュメントなどで加工中あるいは完成したものなど。<br><br>(B)配信可能なアセット(私の場合はDropbox):<br>(A)の内で、他者にわたることを前提とした、合法なコンテンツ</p>



<p>(C)配信する予定のあるアセット(私の場合は、Dropbox、Xserver、自宅サーバー、pCloud、Vimeo、YouTube):<br>(B)の内で、配信にマッチするように調整を済ませたコンテンツ</p>



<p>(D)配信できる状態にスタンバイしたアセット(私の場合は、Dropbox、Xserver、自宅サーバー、pCloud、Vimeo、YouTube):<br>(C)の内で、共有URLを持って、ランチャー（発射台）にセットされたアセット<br><br>※(C)と(D)の違いは、ステータス（公開、非公開）の違い。</p>



<p><br>以上のようになります。<br>このうち、(B)について、Dropboxの中にフォルダ(mmedia pmedia)を設定しています。このフォルダの整理以降が、今シリーズの対象になります。<br><br></p>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1u3IsAxH-_6Ex4Wrjv3CgmHDINUKS6V8GCzEf3SqrKVI/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vR9rDTau5P09ZIvdFNlART_vbCoCyUe2lcGuCFpAtS9fslIKhNUu64IebZmZ51IG6aI3pSNl_Q86Xkg/pub?w=960&#038;h=720"
></a>



<h3 class="wp-block-heading">メディアライブラリは商社の本社機能のようなもの：</h3>



<p>図書館とメディアライブラリの違いを考えてみます。<br>一言でいって、サービス部門の設置場所が、違ってきます。図書館は書籍を受け渡しするためサービス部門は各図書館内に必要です。書籍は質量がありますから。<br>それに対して、メディアライブラリは、動画、画像、テキストといった、質量がなく即座に複製移動できる、情報アセットを受け渡しするサービス部門です。従って、メディアライブラリは、アセットが複数の場所に存在していても、「何がどこにあるか」というメタ情報(台帳のようなもの)があればいいだけです。それは一ヶ所あれば十分です。</p>



<p>メディアライブラリはGoogleドライブを使っています。Googleドライブには、動画、画像、テキストといったアセット自体は置きません。置くのは、そのアセットの特性や特徴を記録したアセット情報(台帳)だけです。メタデータだけです。<br>またGoogleドライブには、GASやAppSheetなどの指示命令機能がそなわっています。いわば、商社の本社機能と言っていいです。</p>



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



<h3 class="wp-block-heading">このシリーズで目指すもの：</h3>



<p>このシリーズでは、DropboxやWordPressサーバーなど、<strong>すでに持っている道具、標準装備されているものをうまく使って</strong>、<br><br>誰でもできる「メディアライブラリのかたち」を提案していきます。</p>



<h3 class="wp-block-heading">こんな方におすすめ：</h3>



<p>この連載は、私自身が実際にメディアライブラリを作ってきた経験をもとに、<br>できるだけわかりやすく紹介していくことを目指しています。</p>



<p>パソコンは<strong>&nbsp;Mac</strong>&nbsp;を使用しており、<br>そのために&nbsp;<strong>AppleScript&nbsp;</strong>や&nbsp;<strong>Automator</strong>&nbsp;など、Mac特有の言語やアプリを使う場面も出てきます。</p>



<p>でも、どれも難しいプログラミングではなく、<br>「ちょっとした工夫で整理がしやすくなる」という発想に近い内容です。</p>



<ul class="wp-block-list">
<li><strong>動画配信やメディア配信を、YouTubeに類するような大手配信サービスに依存したくない方、ひと所に依存したくない方</strong></li>



<li><strong>動画や画像を頻繁に手直ししたい方</strong></li>



<li><strong>共有URLの提供を、自分として一本化したい方</strong></li>



<li><strong>メディアコンテンツの作成からメディアアセットの管理を、一貫して行いたい方</strong></li>



<li><strong>そうした<a rel="noopener" target="_blank" href="https://ja.wikipedia.org/wiki/デジタル資産管理">メディアアセット管理システム(MAM)<span class="fa fa-external-link external-icon anchor-icon"></span></a>を、あまりお金を掛けないで、ハンドメイドで小規模に実現したい方</strong></li>
</ul>



<p>そんな方にとって、きっとヒントになるシリーズになると思います。</p>



<p><br><br>次回からは、実際の構造や工夫について、図や例をまじえながらお伝えしていきます。</p>



<h3 class="wp-block-heading">準備するもの：</h3>



<p>Mac、Dropbox、Googleドライブ、AppSheet、AppleScript、Python、GAS、ShellScript<br>です。DropboxおよびGoogleドライブは最下位の有料版で十分。</p>



<h3 class="wp-block-heading">次回予告：</h3>



<p><strong>第2章では、「メディアライブラリへの登録〜パイプライン処理〜</strong>」についてご紹介します。<br></p>



<p>&#x27a1; <a href="https://imakat.com/2025/04/08/25796/">第2章を読む</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-center"><a href="https://imakat.com/media_library1" target="_blank">&#x1f517; 目次ページへ戻る</a></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">25693</post-id>	</item>
		<item>
		<title>Xserverにあるデータをローカルへ自動定期バックアップする(SFTP、SSH接続)</title>
		<link>https://imakat.com/2024/11/24/24352/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Sun, 24 Nov 2024 05:29:53 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[AppleScript]]></category>
		<category><![CDATA[SFTP]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Xserver]]></category>
		<category><![CDATA[Transmit5]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=24352</guid>

					<description><![CDATA[2024.12月から、一番下のまとめに書いた、Xserver内に圧縮zipファイルを作成する→次にMacのrsyncでダウンロードする方法へ移行しています。 はじめに 今回は、SynologyNASとMac miniのフ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>2024.12月から、一番下のまとめに書いた、<a href="https://imakat.com/?pubtxt=xserver内に圧縮zipを作成_pub.txt" target="_blank">Xserver内に圧縮zipファイルを作成する</a>→<a href="https://imakat.com/?pubtxt=rsync_xserverからdropboxへダウンロード_pub.txt" target="_blank">次にMacのrsyncでダウンロードする</a>方法へ移行しています。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><strong>はじめに</strong></p>



<p>今回は、SynologyNASとMac miniのファイル管理システムにおいて、下の赤枠で囲んだ部分について紹介します。AppleシリコンのMac miniを常時稼働してサーバーのように使う人が、これからどんどん増えるように思えます。そうなってくると、今回紹介するミニシステムは、定番の一つになると想像します。</p>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1zyDa-hDxh5-aNt5-9aDLsDprjrzV7J0K8PdMXBYR9m0/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vSOo5k3T4l8Gh1YAyEaXTwb0nA7Q0Ri3Cj5nM4bY__DWTa8goed_LYyTl7NttePs__4Tui7KjZ0eNJl/pub?w=960&#038;h=720"
></a>



<p><strong>Xserverにあるデータをローカルへバックアップする(SFTP、SSH接続)</strong></p>



<p>Xserverは、契約すれば無料で１週間分のバックアップがついてくるから、なんでわざわざローカルにバックアップなんか必要なの？</p>



<p>そのような疑問は確かに起こります。</p>



<p>Xserverの無料バックアップからの復元は、復元を申請したあとに心配がおきます。つまり、いつ処理が開始していつ頃終了するのか分からないので、ただ待つしかないのです。私の経験からは30分で済むこともあれば3時間かかることもあります。時間が読めないこと、それは結構ストレスです。またその時間を大幅に短縮したいです。出来れば10分以内。そのためには、前夜の状態のファイルがローカルにバックアップされていれば大丈夫でしょう。そのバックアップするフォルダは、WordPressのフォルダが対象なので、uploadsとthemesがあれば十分でしょう。</p>



<p>以前に、Transmit5のFTPを使ってXserverへアップロードする方法を紹介しましたが、今回は、Transmit5のSFTPすなわちSSH接続を使って、Xserverからダウンロードを行う方法、しかもそれを自動運転にする方法を紹介します。</p>



<p>なかなかMacを使ったSFTP、SSH接続の日本語での解説ブログやYouTubeは見当たりませんね。</p>



<p>５手順と長くなりますが、よろしくお付き合いください。</p>



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



<h4 class="wp-block-heading"><strong>手順１ 　XserverのSSH接続を開通させる</strong></h4>



<p><strong>（１）　MacでSSHキーを作成</strong><br>以下を行うと、id_rsa（秘密鍵）とid_rsa.pub（公開鍵）が作成されます。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>ssh-keygen -t rsa -b 4096 -C &#8220;your-email@example.com&#8221;</td></tr></tbody></table></figure>



<p><strong>（２）　公開鍵をXserverに登録</strong></p>



<p>id_rsa.pubの内容をコピーして、Xserverの管理画面に登録します。</p>



<p>１）id_rsa.pubは、隠しファイルになっているので、Finderの右上の虫眼鏡にid_rsa.pubと入れて、見つけてください。それを、テキストエディット.appで開く→内容をコピー。</p>



<p>２）Xserverのサイトに入る→サーバーパネル→SSH設定をON</p>



<p>&nbsp;初期設定の段階なので、とりあえず「ON[すべてのアクセスを許可] 」を選択します。<br>※2024/11/25現在、国内からのアクセスのみ許可に変更</p>



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



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



<p><strong>（３）公開鍵登録・更新</strong>→（２）１）でコピーした公開鍵をペースト→確認画面へ進む→登録する。</p>



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



<p><br><br><strong>（４）　接続の確認</strong></p>



<p>ターミナルへ以下を入れて接続してください。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>ssh -i ~/.ssh/id_rsa -p 10022 your-username@your-server</td></tr></tbody></table></figure>



<p>Xserverの場合、</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>ssh -i ~/.ssh/id_rsa -p 10022 your-username@your-username.xsrv.jp</td></tr></tbody></table></figure>



<p>となります。</p>



<p>接続が成功したら、一旦、ターミナルはexitを入れて終了してください。</p>



<h4 class="wp-block-heading"><strong>手順２　Transmit5アプリを使って、SFTPにて、単独でバックアップできるようにする</strong></h4>



<p>赤く消してあるところは、ユーザ名が入ります。１（１）で作成した秘密鍵、id_rsa、を、パスワードまたはキーの右側のキーのアイコンをクリックして認証鍵を入れるボックスを開き、その中に登録します。登録は、このボックスの下にある＋のマークをクリックすると、親切に通常は非表示のフォルダも表示されてid_rsaが選択出来ます。登録されたらid_rsaの上をタップすると、キーに収まります。<br>XserverにおけるSSH設定の条件は<a rel="noopener" target="_blank" href="https://www.xserver.ne.jp/manual/man_server_ssh.php">ここに<span class="fa fa-external-link external-icon anchor-icon"></span></a>記載されています。</p>



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



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



<p>上と同様に、SFTP_uploadsも作成します。<br><br></p>



<h4 class="wp-block-heading"><strong>手順３　バックアップ用のアプリを作る</strong></h4>



<p>上で作った単独バックアップを起動させて動作した後に終了する流れを、Automatorで一つのアプリとして作成します。まず、SFTP_themesは以下です。</p>



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



<p>Automatorで新規作成→アプリケーションを選び、Transmit.appを選びます。接続先の選択肢にTransmit5にお気に入り登録したものが出てくるので、SFTP_themesを選びます。すると、サーバ、ユーザ名、パスワード、ポート、プロトコルは、引っ張ってきて入ります。それ以下の項目は設定します。</p>



<p><strong>同期の方向：ダウンロード（今回の場合はダウンロードです。ここは要注意！！）</strong></p>



<p>比較の方法：変更日</p>



<p>スキップ項目：なし</p>



<p>ローカルパス：これは、Finderで探して設定します。自分があとで扱いやすい場所。</p>



<p>オプション：同期先のみに存在する項目は削除する。（単純なバックアップ目的のダウンロードは、チェックを外します）</p>



<p>リモートパス：リモートサーバとの時差を自動で調整する。一応チェックを入れておきます。</p>



<p>処理が済んだら、Transmit5を終了→Automatorを終了します。</p>



<p>次に同様に、uploadsフォルダのダウンロードである　SFTP_uploadsも同様に設定します。このように小分けする理由ですが、ダウンロードは結構、エラーが起きやすく、あまり大きなフォルダですとやり直しに多大な時間が掛かります。ですので、例えば初期ダウンロードで１０分程度で済むサイズで区切るとか、小分けにした方がいいです。</p>



<h4 class="wp-block-heading"><strong><strong>手順４　複数の単独アプリを流れとして組む</strong></strong></h4>



<p>Automatorで作成した単独アプリを流れとして組み込みます。なお、<strong>完了の通知としてメールを使います</strong>。夜中の自動処理を設定すると、本当に処理が行われているかどうか心配になります。メール一つあるだけで安心します。</p>



<p>AppleScriptを使います。まとめたアプリをSFTP_themes_and_uploads.appとします。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>&#8212; スクリプト開始<br>on run<br>	&#8212; SFTP_themes.app を起動<br>	tell application &#8220;SFTP_themes&#8221;<br>		activate<br>	end tell<br>	<br>	&#8212; アプリが終了するまで待機<br>	delay 10 &#8212; アプリの自動終了までの目安時間（必要に応じて調整）<br>	<br>	&#8212; 1分間待機<br>	delay 70<br>	<br>	&#8212; SFTP_uploads.app を起動<br>	tell application &#8220;SFTP_uploads&#8221;<br>		activate<br>	end tell<br>	<br>	&#8212; アプリが終了するまで待機<br>	delay 10 &#8212; アプリの自動終了までの目安時間（必要に応じて調整）<br>	<br>	&#8212; メールを作成して送信<br>	tell application &#8220;Mail&#8221;<br>		set newMessage to make new outgoing message with properties {subject:&#8221;SFTP_themes_and_uploadsは完了しました。&#8221;, content:&#8221;M1 Mac自動処理&#8221;, visible:false}<br>		tell newMessage<br>			make new to recipient at end of to recipients with properties {address:&#8221;xxxxxx@gmail.com&#8221;}<br>			send<br>		end tell<br>	end tell<br>end run</td></tr></tbody></table></figure>



<h4 class="wp-block-heading"><strong><strong><strong>手順５　自動処理させるために、カレンダーに組み込む</strong><br><br></strong></strong></h4>



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



<p>Macのカレンダーには、「通知」の機能の中にあるカスタムに、「ファイルを開く」がありここでアプリを起動することができます。</p>



<p>カレンダーからは、アプリは起動するだけで、終了の動作は行いません。終了の動作は、取り付けるアプリの中に組み込まれている必要があります。</p>



<p>開始：日時</p>



<p>終了：日時　ここは、時刻は開始時刻と同じで構いません。</p>



<p>繰り返し：毎日</p>



<p>繰り返し終了：なし</p>



<p>移動時間：なし</p>



<p>通知：カスタム</p>



<p>ファイルを開く　SFTP_themes_and_uploads.app これはアプリケーションフォルダから選択、予定の開始時刻を選択</p>



<p>次に、</p>



<p>Macのシステム設定→プライバシーとセキュリティ→カレンダー→SFTP_themes_uploadsのオプションからフルアクセスにする→カレンダーを終了して再度立ち上げます。</p>



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



<p></p>



<p><strong>その他、まとめ</strong></p>



<p>SFTPによるダウンロードですが、禁止文字の使用など様々な理由でエラーで進まないこともあります。その場合、<strong>Xserver内で、zipファイルに圧縮してからrsyncでダウンロードする</strong>と、順調に行くことが多いです。<br><br><a href="https://imakat.com/?pubtxt=xserver内に圧縮zipを作成_pub.txt" target="_blank">Xserver内に圧縮zipファイルを作成する</a>→<a href="https://imakat.com/?pubtxt=rsync_xserverからdropboxへダウンロード_pub.txt" target="_blank">次にMacのrsyncでダウンロードする</a>方法。</p>



<p>以上が、定期的自動的に、外部サーバーにあるデータを、ローカルにダウンロードする流れになります。こうした処理が自宅で簡単に行えるようになってきたのも、Macが、特にMac miniが省電力になり、常時稼働が可能になってきたことが大きいです。</p>



<p>以上</p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">24352</post-id>	</item>
		<item>
		<title>MacからMacを操作する〜画面共有の利用〜</title>
		<link>https://imakat.com/2024/11/17/24259/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Sun, 17 Nov 2024 07:59:09 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[SynologyNAS]]></category>
		<category><![CDATA[AppleScript]]></category>
		<category><![CDATA[画面共有]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=24259</guid>

					<description><![CDATA[2026.2.22：最近Macminiを常時稼働させてAIエージェントとして使うのがブームになっているようです。というか一家に一台、24時間365日稼働させる、汎用のコンピュータがある時代になったということですね。このM [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>2026.2.22：<br>最近Macminiを常時稼働させてAIエージェントとして使うのがブームになっているようです。というか一家に一台、24時間365日稼働させる、汎用のコンピュータがある時代になったということですね。このMacからMacを操作する方法はとても役にたつと思います。それから裏方のMacminiは、そんなに迅速に動いてくれる必要はありません。24時間365日使って安定して作業してくれればいいわけで、M1のMacminiでも、まだまだ十分に使えます。つまり安いです。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>SynologyNASとM1 Mac miniによるファイル管理システムを動かすにあたり、前回は、Jump DesktopによるiPad iPhoneからM1 Mac miniのリモート操作を紹介しましたが、それは実は頻度は低く、実際は90%以上は、今回紹介する、画面共有によるM2 Mac miniからM1 Mac miniのリモート操作になると思います。</p>



<p>あと、いつもいつも、M2 Mac miniと書くのも面倒なこともあり、要は、「Mac」と一言で括れる共通事項については、面倒に感じた時はMacと書くようにします。小さい話です。</p>



<p>ただ、モニター、マウス、キーボードといった周辺機器が何もないのがMac miniですし、省電力になり常時稼働が平気になったのがM1以降ですので、M1 Mac miniが裸っぽの原点になります。M1以降ならMacbookなどラップトップも全てavailableなチキチキマシーンです。</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=39" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" poster="https://www.dropbox.com/scl/fi/w8zqic0a3d8okwp3dfh7t/screenshot_2024-11-17_14.06.30.png?rlkey=mbfmdsofndrvc6cybqhnofdpd&#038;raw=1" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=cnN9m7vL.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=rcVApp2z.vtt" label="日本語" srclang="ja" kind="subtitles"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><div class="dr5emd-sublist"><details><summary>字幕一覧(クリック)</summary> <p>
(<a href="#" class="imk-cue" data-seek="0:00">00:00:00</a>) 1) 「Macで別のMacを操作する　画面共有の利用」<br>
(<a href="#" class="imk-cue" data-seek="0:07">00:00:07</a>) 2) この図は、MacとSynologyNASの連携システムです。<br>
(<a href="#" class="imk-cue" data-seek="0:11">00:00:11</a>) 3) 今回は、その中から、この部分。M2Macから画面共有でM1Macを操作してみます。<br>
(<a href="#" class="imk-cue" data-seek="0:17">00:00:17</a>) 4) M2MacからSTREAM DECKで、画面共有を起動します。<br>
(<a href="#" class="imk-cue" data-seek="0:23">00:00:23</a>) 5) M1Macが表示されます。<br>
(<a href="#" class="imk-cue" data-seek="0:33">00:00:33</a>) 6) M2Macのメモアプリを立ち上げます。<br>
(<a href="#" class="imk-cue" data-seek="0:41">00:00:41</a>) 7) こちらはM1Macのメモアプリです。<br>
(<a href="#" class="imk-cue" data-seek="0:46">00:00:46</a>) 8) 文字を打ち込んでみます。　<br>
(<a href="#" class="imk-cue" data-seek="1:08">00:01:08</a>) 9) M2Macのメモアプリでも、当然、同期して表示されます。<br>
(<a href="#" class="imk-cue" data-seek="1:20">00:01:20</a>) 10) M1Macで文字を打ち込みます。<br>
(<a href="#" class="imk-cue" data-seek="1:27">00:01:27</a>) 11) M2 Macの表示も同じ。<br>
(<a href="#" class="imk-cue" data-seek="1:31">00:01:31</a>) 12) M2Macの文字を修正します。<br>
(<a href="#" class="imk-cue" data-seek="1:34">00:01:34</a>) 13) M1Macも同じ。<br>
(<a href="#" class="imk-cue" data-seek="1:36">00:01:36</a>) 14) 有線LAN接続ですが、遅延はほとんど感じません。<br>
(<a href="#" class="imk-cue" data-seek="1:39">00:01:39</a>) 15) 画面共有は右端に新たなデスクトップが作られます。<br>
(<a href="#" class="imk-cue" data-seek="1:42">00:01:42</a>) 16) 私の場合は、デスクトップは、一つだけでいいかも知れません。<br>
(<a href="#" class="imk-cue" data-seek="1:47">00:01:47</a>) 17) こんなふうに移動する必要もなくなります。後で削除します。<br>
(<a href="#" class="imk-cue" data-seek="1:54">00:01:54</a>) 18) 画面共有でも、ほとんど違和感なく操作ができます。<br>
(<a href="#" class="imk-cue" data-seek="1:59">00:01:59</a>) 19) 以上です。<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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

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

    /* -----------------------------------------------
       1. 動画の保護機能（右クリック禁止・DL防止）
       ----------------------------------------------- */
    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video');
      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. 字幕制御＆ハイライト機能（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;
    }

    /* -----------------------------------------------
       監視タイマー
       ----------------------------------------------- */
    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo(); // ★dynamic2は保護を維持
      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>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1sA8k91Rvdzz2lQjwS-qf5Du5m3zMAtIfBgxbU5owDAI/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vQVadRDz9qxpnB1eSLozgSp1XVvbYXwNJCXf_Zr-P1rLXz7Nj84Fx0aN9yqmG-PEG5usZOnLHQvoshz/pub?w=960&#038;h=720"
></a>



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



<p>MacからMacを操作する方法には、Appleが提供するものとしては2つあって、一つは今回の「画面共有」ですが、あと一つは「リモートマネジメント」があります。「リモートマネジメント」は本格的な方法で専用アプリが必要になります。「リモートマネジメント」は大規模な企業ネットワークでIT担当者が使用するような仕組みなので、ちょっと縁遠いです。自宅でDIYできる範囲が、私のテリトリーです。</p>



<h4 class="wp-block-heading">１　STREAM DECKの利用</h4>



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



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>スクリプト要約：画面共有アプリを自動操作し、指定Mac（yyyyyyyy-macminim1）へ接続するAppleScript。アプリ起動後3秒待機し、メニューバーから最近接続先を選択。接続確立まで待ち、パスコード「&lt;あなたのパスワード&gt;」を自動入力してEnterを押す。その後、ウィンドウ表示を待ってフルスクリーン化する一連の手順をスクリプト化している。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=M1Macの画面共有を起動する_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></tbody></table></figure>



<p>STREAM DECKに画面共有を立ち上げるスクリプトを登録しています。その理由は、画面をスムーズに立ち上げるために、手順と細かいチューニングを決めておきたいからです。主なものは２点あります。</p>



<p>一つ目は、パスコードを入れる前の待ち時間のチューニングです。パスコードも自動で打ち込むようにしてあるのですが、タイミングが合わないと画面が止まってしまいます。例えて言うと、電車の出発が早すぎると、乗り遅れてホームに置き去りにされたままになってしまいます。そこで電車を遅らせます。一応delay５秒にしておきます。もちろんその、次の電車に乗ればいいわけで、つまり少々待って、もう一度自分でSTREAM DECKのボタンを押せば、大抵OKとは申せますが。</p>



<p>二つ目は、ウインドウをフルスクリーンに設定することです。その理由は、起動した最初は、ウインドウは画面上に浮いたような状態でして、これですとカーソルがウインドウの中と外を行き交うので少々脳細胞が混乱してストレスです。割り切ってウインドウをフルスクリーンにして固定した方がマウスの操作がラクです。画面共有を立ち上げると、画面共有という名のデスクトップが追加されるので他のアプリへの支障はありません。</p>



<p>細かい話になりますが、スクリプトの最後のステップに、ウインドウをフルスクリーンにするアクションがあります。その際、フルスクリーンボタンの番号は、表示場所とは必ずしも一致しない点は、記憶に留めておくと良いでしょう。現状、ウインドウのボタンは3つ並んでいます。そのうちで今回目的のフルスクリーンのボタンは右端にあります。3つあってそのうち右端なので、ふつうは、１または３だな、と思うじゃありませんか。ところが違うのですね。正解は２です。今のところ、そのような仕様になっています。試行錯誤で見つけ出すことになります。</p>



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



<p></p>



<p></p>



<h4 class="wp-block-heading">２　そのまま相手を再起動できる</h4>



<p>M1 Mac miniが重いような気がした時、再起動をしますよね。再起動ができるのです。M1 Mac mini画面の左上から再起動をしますと、なんと画面共有を維持した状態で、そのまま戻ってくれます。これが実に快適です。</p>



<h4 class="wp-block-heading">３　フルスクリーンの分離はマウスで上端を押し上げる</h4>



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



<p>作業性の関係で、この共有画面を分離して、一つのウインドウで表示したい場合があります。その場合に、ちょっとコツが要ります。まず、マウスで画面の上端を持ち上げるようにするとバーが出てきます。そのバーの左にある緑のボタンを押すと、フルスクリーンの解除ができます。</p>



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



<p>MacからMacをコントロールするのが、やはり一番相性がいいですね。</p>



<p>以上</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">24259</post-id>	</item>
		<item>
		<title>iPadからMacを操作する〜Jump Desktopの利用〜</title>
		<link>https://imakat.com/2024/11/06/24047/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Tue, 05 Nov 2024 23:20:38 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[Jump Desktop]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=24047</guid>

					<description><![CDATA[先の投稿で、Mac mini M1をファイル管理用Macとして常時稼働する運用が、やりやすくなってきたと話しましたが、こうなってくると、どこか離れた場所からリモートで、Macのファイルの操作を行えるようにしたいです。 J [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>先の投稿で、Mac mini M1をファイル管理用Macとして常時稼働する運用が、やりやすくなってきたと話しましたが、こうなってくると、どこか離れた場所からリモートで、Macのファイルの操作を行えるようにしたいです。</p>



<p>Jump Desktopというアプリを使って、iPadからMacの操作が出来ます。</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=34" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" poster="https://imakat.com/rd.php?id=Zd1sAeug.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=xHh3YTts.mov" type="video/mp4">  <track src="https://imakat.com/rd.php?id=uMF70Tzz.vtt" label="日本語" srclang="ja" kind="subtitles"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><div class="dr5emd-sublist"><details><summary>字幕一覧(クリック)</summary> <p>
(<a href="#" class="imk-cue" data-seek="0:00">00:00:00</a>) 1) iPadからMacを操作する〜Jump Desktopの利用〜<br>
(<a href="#" class="imk-cue" data-seek="0:07">00:00:07</a>) 2) いきなり、細かい図解で申し訳ありません。<br>
(<a href="#" class="imk-cue" data-seek="0:12">00:00:12</a>) 3) M1 Mac miniとSynologyNASを連携させて、ファイル管理を行います。<br>
(<a href="#" class="imk-cue" data-seek="0:18">00:00:18</a>) 4) M1 Mac miniとSynologyNASの構成は、こんな形になります。<br>
(<a href="#" class="imk-cue" data-seek="0:28">00:00:28</a>) 5) 今回は、iPadにインストールをしたJumpDesktopを使って、M1 Mac miniを操作する場面の紹介です。<br>
(<a href="#" class="imk-cue" data-seek="0:40">00:00:40</a>) 6) iPadの画面に移動します。<br>
(<a href="#" class="imk-cue" data-seek="0:45">00:00:45</a>) 7) この「Jump」というアプリを使います。<br>
(<a href="#" class="imk-cue" data-seek="0:50">00:00:50</a>) 8) 既に登録してあるMacが表示されます。<br>
(<a href="#" class="imk-cue" data-seek="0:54">00:00:54</a>) 9) M1 Macminiを選びます。<br>
(<a href="#" class="imk-cue" data-seek="1:03">00:01:03</a>) 10) サクッと繋がり、M1 Macminiの画面になります。<br>
(<a href="#" class="imk-cue" data-seek="1:15">00:01:15</a>) 11) Finderを開きます。<br>
(<a href="#" class="imk-cue" data-seek="1:32">00:01:32</a>) 12) テストのvttファイルを開いてみます。<br>
(<a href="#" class="imk-cue" data-seek="1:42">00:01:42</a>) 13) 文字列を修正してみます。<br>
(<a href="#" class="imk-cue" data-seek="1:48">00:01:48</a>) 14) ファイルを保存します。<br>
(<a href="#" class="imk-cue" data-seek="1:56">00:01:56</a>) 15) すると、既に登録してあるアプリにより、変化したvttは、外部サーバーへ更新されます。<br>
(<a href="#" class="imk-cue" data-seek="2:06">00:02:06</a>) 16) 次にファイルの上で2本指でタップをします。するとMac上では右クリックに扱いになります。「Dropboxリンクのコピー」を選びます。<br>
(<a href="#" class="imk-cue" data-seek="2:14">00:02:14</a>) 17) 「メモ」アプリを起動して、2本指でタップをして、ペーストを選びます。<br>
(<a href="#" class="imk-cue" data-seek="2:23">00:02:23</a>) 18) dl=0をraw=1に書き換えます。<br>
(<a href="#" class="imk-cue" data-seek="2:34">00:02:34</a>) 19) クリックして表示します。<br>
(<a href="#" class="imk-cue" data-seek="2:45">00:02:45</a>) 20) 割と簡単に、iPadからMacのファイル操作が、行えます。このiPadはiPadPro12.9です。小さいiPadでは操作しづらいかもしれません。以上です。<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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

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

    /* -----------------------------------------------
       1. 動画の保護機能（右クリック禁止・DL防止）
       ----------------------------------------------- */
    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video');
      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. 字幕制御＆ハイライト機能（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;
    }

    /* -----------------------------------------------
       監視タイマー
       ----------------------------------------------- */
    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo(); // ★dynamic2は保護を維持
      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>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1rtZHShY2x5RIp2mTvbVSi-0apkEbHxyjLlwXuZrAH6A/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vSpzj90zTM8mhr_gTOgPgDtvmeAdNeu7VNMuyNgaCccCj5BxuLsOYngLdfA6Qwt9EzfISbfzlp3GGfw/pub?w=960&#038;h=720"
></a>



<p>App Storeで購入ができます。24年11月現在、円安のせいか2,200円(買い切り)と高めになっていますが、同じAppleIDなら複数台のiPad、iPhoneからアクセスできますので、それなりにお得感はあります。JumpDesktop以外にも、こうしたリモート操作のアプリはあると思いますが、安全を考えてApp Storeから購入するのがいいと思います。</p>



<h4 class="wp-block-heading">iPad miniやiPhoneでは、たくさんの作業は疲れるでしょう。</h4>



<p>こうしたリモートでの変更作業も、本当は、iPad miniやiPhoneで行えればいいのですが、ピンポイントの修正作業だけであればそれでいいのですが、修正数が多くなると小さくて疲れると思います。上の動画ではiPadPro12.9を使っていますが、これであれば、ピンチアウトを使いながら、まずまずサクサクと操作が出来ます。一瞬、マウスの右クリックの代替はどうする？！と迷いますが、<strong>2本指でタップする</strong>と代替になります。</p>



<p>以上</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">24047</post-id>	</item>
		<item>
		<title>【Mac】M1 Mac miniと、M2 Mac miniを使い分けました。</title>
		<link>https://imakat.com/2024/10/30/23866/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Wed, 30 Oct 2024 06:42:38 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Dropbox]]></category>
		<category><![CDATA[Mac mini]]></category>
		<category><![CDATA[GoogleDrive]]></category>
		<category><![CDATA[Apple Intelligence]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=23866</guid>

					<description><![CDATA[制作用のパソコンは、フリーズが多くなってしまう。再起動がつきもの。 音楽制作や動画制作では、アプリのバグに振り回されて、結構、頻繁にフリーズして、Macを再起動することが起きます。その作業の最中に、並行して、Hazelや [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=IfXpZODc.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=IfXpZODc.png" alt="" style="width:171px;height:auto"/></a></figure>



<h5 class="wp-block-heading"><strong>制作用のパソコンは、フリーズが多くなってしまう。再起動がつきもの。</strong></h5>



<p>音楽制作や動画制作では、アプリのバグに振り回されて、結構、頻繁にフリーズして、Macを再起動することが起きます。その作業の最中に、並行して、<a rel="noopener" target="_blank" href="https://note.com/fuun_inc/n/ndf99d4675c46">Hazel<span class="fa fa-external-link external-icon anchor-icon"></span></a>やAppleScriptなどのファイル更新の自動処理を行っているときに、そちらも、中断させられてしまいます。その逆もあります。いずれも、やり直しになります。</p>



<h5 class="wp-block-heading"><strong>ファイルの更新処理は切り離したい。</strong></h5>



<p>やはり、制作類の作業を行うMacと、ファイル更新処理を行うMacなどのコンピュータは独立させた方が、全体としての安定性が向上します。</p>



<p>但し、<a rel="noopener" target="_blank" href="https://pc.watch.impress.co.jp/docs/column/macinfo/1356257.html">クイックアクション<span class="fa fa-external-link external-icon anchor-icon"></span></a>などの、いわゆる生産性を上げるための操作は、制作作業Mac側で行い、ファイル更新処理Macの様子を別ウインドウで表示して横目で監視するようなやり方でも、問題なく使えるでしょう(例：上の写真)。</p>



<h5 class="wp-block-heading"><strong>ファイルサーバーとしても活用</strong></h5>



<p>M1以降のMacはほとんど発熱もなく消費電力も小さいので、少なくともファイル更新処理Macは常時稼働で問題なく、いわばファイルサーバーのようにSynologyNASの頭脳のような位置付けで使用するのが相性が良さそうです。</p>



<h5 class="wp-block-heading"><strong>Mac miniもそうだが、Macは進歩はすれど安心して継承できる。</strong></h5>



<p>つい先日、<em><a rel="noopener" target="_blank" href="https://www.apple.com/jp/newsroom/2024/10/apples-new-mac-mini-is-more-mighty-more-mini-and-built-for-apple-intelligence/">M4 Mac mini<span class="fa fa-external-link external-icon anchor-icon"></span></a></em>が発表され、どんどんコンパクトに強力になっていくことに驚いていますが、方向は、そうなるのだろうなと想像はしていました。</p>



<p>つまりMacminiは、サーバーだと思えば、電源スイッチを底面にしたのもガッテンです。NASの電源スイッチなど１年に1回触るかどうかです。</p>



<p>しかしよくよく考えて、最新鋭のM4 Mac miniをサーバー的に使うのは勿体無いわけで、もしM4 Mac miniを制作系の作業で使うなら、アプリ側の更新の遅れで頻繁なフリーズに悩まされて、何度も電源スイッチの入り切りを行うことになるわけですから、いっそのことスイッチ付きテーブルタップを、自分の一番使いやすい位置に取り付ける、そういう結論になるのだと思います。まあ小さい話です。</p>



<h5 class="wp-block-heading"><strong>先入先出の作業方法をApple Intelligenceに考えてもらいたい</strong>。</h5>



<p>OSは今回、１世代前のSonomaにアップしました。それは１年遅れで信頼性を確保したいからです。次のOSの更新を焦るつもりはありません。ハードに依存します。ハードは、いずれは、M4 Macminiなどがメイン機になり、今あるM2 Macminiがサブになる、古いものから順に引退する、つまり先入先出になるわけです。課題は、特に音楽制作は、Mac本体内のディスク容量を食うのでM2 Macminiは1TBとしてきました。どういうことかと言うと、音楽制作のDAWは、多種多様な音源をロードして使います。そのロードに時間がかかるのです。その音源のうち音源データ部分は外部SSDなどへ逃すにしても、アプリケーション部分は本体内に残すようにしないと、ロード時間を短くできないのです。前述したように、そのDAW、音源アプリさらにはOSとハードとの間で、バグや相性不具合が生じて強制的な起動が頻発するわけです。どうにかならないかとストレスを抱えます。しかし、M4 Macmini1TBともなると、また高価格になっていくので、なかなか、ついていけませんね。&nbsp; 次は何とかメイン機のディスク容量を512GBで抑制できないか、そのように改善したいです。その診断と解決策をApple Intelligenceに考えてもらえたら助かりますね。<br></p>



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



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1wR0pNTej5OTjO6YDLAl1n4Qv4aPU2XUVy0Fa9nvfzqw/edit?usp=sharing">
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vRx4i39wHFUdJESf6--9Ye-wHGA2aCyg3duM3o5cEBaHc3qfL70csV408TdEiPBee62KSTD63yaxKTl/pub?w=960&#038;h=720"
></a>



<h4 class="wp-block-heading">１　<strong>DropboxとGoogleDriveの間のデータの更新方法について</strong></h4>



<p>クラウドストレージとクラウドストレージの同期を行うのにはどうするか(※1)。それまた別のクラウドストレージによるサービスもあるのですが、両方ともデータはローカルにあり、SSDの中あるいはNASの中にあるので、ローカルで更新を行う方法を選択します。<a rel="noopener" target="_blank" href="https://atmarkit.itmedia.co.jp/ait/articles/1702/02/news031.html">rsync<span class="fa fa-external-link external-icon anchor-icon"></span></a>を使う方法が一般的です。これはNASの中でもMacのSSDの中でも使用できます。NASの中で行う方法について、別の投稿で、説明するつもりです。</p>



<p>更新の方向ですが、Dropboxが更新されたらGoogleDriveが更新される、from Dropbox to GoogleDriveにします。つまり、基本的なローカルでのファイル作成作業はDropboxで行うこととします。</p>



<p>※１：SynologyNASのアプリにCloudSyncがありますが、これは、ローカルのフォルダやファイルに対しては、一つだけのクラウドストレージしか指定できません。</p>



<h4 class="wp-block-heading">２　<strong>GoogleDriveも使う理由</strong></h4>



<p>それならDropboxだけでいいではないか、と思われるところですが、それは早計でして、GoogleDriveを使う理由は、AppSheetを使いたい、GASを使いたい、スプレッドシートを使いたい、それらのためにGoogleDriveが必要になるからです。<br>いえそれなら、GoogleDriveだけでいいではないか。と思われるでしょうが、これまた勇み足でして、字幕の扱いがうまくいかないため動画をリンクで使うのが困難。ならDropboxの方がマシということが大きいです(<a href="https://imakat.com/vm5?movid=905195687" target="_blank">解説&#x1f3a5;</a>)。</p>



<h4 class="wp-block-heading">３　Dropboxデスクトップアプリによるファイル操作がラク</h4>



<p>Dropboxにある写真や動画をWordPressへリンクするためにDropboxリンクを取得しようとするとき、Dropbox.comのサイトから入るのはちょっと手間がかかり過ぎです。Dropboxのローカルファイルから右クリックで取得できれば簡単です。SynologyNASは、そのフォルダをDropboxと同期することはできますがしかし、SynologyNASのDropboxのフォルダからは、それを右クリックしてもDropboxリンクの取得はできません。Dropboxデスクトップアプリが提供されていないためです。この辺りが、SynologyNASをパソコン的に使えないと感じる部分です。</p>



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



<p>その点、MacやWindowsでは、デスクトップアプリが提供されているため、以下のように、MacのFinderからでも、Dropboxリンクが取得できます。GoogleDriveでも同様に、リンク取得が可能です。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=ZZh7TyOF.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=ZZh7TyOF.png" alt="" style="width:800px;height:auto"/></a><figcaption class="wp-element-caption">M1 Mac mini  一部、高画質での提供の動画は視聴できません。</figcaption></figure>



<p>M1 Mac miniは、M2 Mac miniからの画面共有(<a href="https://imakat.com/script_list/?pubtxt=M1Macの画面共有を起動する_pub.txt" target="_blank">スクリプト&#x1f4d2;</a>)の形にしています。共用のモニター、キーボード、マウスで操作しています。</p>



<p></p>



<p>以上</p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">23866</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[Mac]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[スマホ]]></category>
		<category><![CDATA[字幕]]></category>
		<category><![CDATA[Windows]]></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; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" 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"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

  <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>
		<item>
		<title>【Mac】複数デバイスを取り込んだ動画づくり</title>
		<link>https://imakat.com/2024/09/02/23609/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Sun, 01 Sep 2024 22:55:57 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=23609</guid>

					<description><![CDATA[以前のブログでは、有線接続の有用性について解説しました。その中で、一つの完成形として、Mac、iPad、iPhone、Webカメラなど複数デバイスを有線接続した方法について、紹介しました。これは、その実施動画です。接続方 [&#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=54" 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; }
            .video-wrap{position:relative;width:100%;margin:0 auto}
            figure.wp-block-video.aligncenter{
              width:100%;
              max-width:min(var(--dr5emd-max, 1920px), 98vw);
              margin:0 auto;
            }
            #subtitleOverlay{
              position:absolute; left:0; right:0; bottom:6%;
              padding:0 2%; text-align:center; pointer-events:none; z-index:2;
            }
            #subtitleOverlay .band{
              display:inline-block; background:rgba(0,0,0,0.35);
              padding:6px 10px; border-radius:8px; max-width:96%;
              margin:0 auto; box-shadow:0 1px 2px rgba(0,0,0,0.15);
            }
            #subtitleOverlay .overlay-cue{
              color:#fff; font-weight:600;
              font-size:clamp(16px, 3.6vw, 32px);
              line-height:1.32; white-space:pre-wrap; margin:2px 0;
              -webkit-text-stroke:.6px rgba(0,0,0,.7);
              text-shadow:-1px -1px 0 rgba(0,0,0,.6), 1px -1px 0 rgba(0,0,0,.6),
                          -1px  1px 0 rgba(0,0,0,.6), 1px  1px 0 rgba(0,0,0,.6);
            }
            @media (max-width:430px){
              #subtitleOverlay .overlay-cue{ font-size:clamp(16px, 4.2vw, 22px); }
            }
            .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;
            }
            /* ▼ 自動スクロール時のハイライト（文字の太さを標準へ変更） */
            .active-hl {
                background-color: #ffff00 !important;
                color: #ff0000 !important;
                font-weight: normal; /* 標準の太さ */
                border-bottom: 2px solid red;
                display: inline-block;
                border-radius: 2px;
            }
            </style><div class="dr5emd-container"><figure class="wp-block-video aligncenter"><div class="video-wrap"><video id="myVideo" controls controlsList="nodownload" poster="https://imakat.com/rd.php?id=4g6H8ISB.png" playsinline preload="metadata" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=bsMsZJyw.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=syf4VCpQ.vtt" label="日本語" srclang="ja" kind="subtitles"></video><div id="subtitleOverlay" aria-hidden="true"></div></div><script>
document.addEventListener("DOMContentLoaded", function(){
  var video=document.getElementById("myVideo");
  var trackEl=video?video.querySelector("track[kind='subtitles'], track[kind='captions']"):null;
  var overlay=document.getElementById("subtitleOverlay"); if(!video||!overlay) return;
  video.addEventListener("contextmenu", function(e){ e.preventDefault(); return false; }, false);
  function setNative(mode){
    try{
      if(video.textTracks && video.textTracks.length){
        for(var i=0;i<video.textTracks.length;i++){ video.textTracks[i].mode = mode; }
      }
      if(trackEl && trackEl.track) trackEl.track.mode = mode;
    }catch(e){}
  }
  var isOverlay=true,lastSig="";
  function sig(active){if(!active||active.length===0)return"";var a=[];for(var i=0;i<active.length;i++){var c=active[i];a.push([c.startTime,c.endTime,c.text].join("|"));}return a.join("||");}
  function cueLine(c){var d=document.createElement("div");d.className="overlay-cue";d.setAttribute("translate","yes");if(typeof c.getCueAsHTML==="function")d.appendChild(c.getCueAsHTML());else d.textContent=c.text;return d;}
  function render(){
    if(!isOverlay || !trackEl || !trackEl.track) return;
    var ac=trackEl.track.activeCues,s=sig(ac); if(s===lastSig) return; lastSig=s;
    overlay.innerHTML=""; if(!ac || ac.length===0) return;
    var b=document.createElement("div"); b.className="band"; b.setAttribute("translate","yes");
    Array.from(ac).sort(function(a,b){return a.startTime-b.startTime;}).forEach(function(c){b.appendChild(cueLine(c));});
    overlay.appendChild(b);
  }
  function useOverlay(){isOverlay=true;overlay.style.display="";setNative("hidden");lastSig="";render();}
  function useNative(){isOverlay=false;overlay.style.display="none";setNative("showing");lastSig="";}
  useOverlay();
  if(trackEl){
    if(trackEl.track){ try{ trackEl.track.addEventListener("cuechange",render); }catch(e){} }
    trackEl.addEventListener("load", function(){ try{ if(trackEl.track) trackEl.track.addEventListener("cuechange",render); }catch(e){} render(); });
  }
  video.addEventListener("loadedmetadata",render);
  function handleWebkitMode(){ var m = video.webkitPresentationMode || "inline"; (m==="picture-in-picture"||m==="fullscreen") ? useNative() : useOverlay(); }
  if("webkitPresentationMode" in video){ video.addEventListener("webkitpresentationmodechanged",handleWebkitMode); handleWebkitMode(); }
  if("webkitCurrentPlaybackTargetIsWireless" in video){
    video.addEventListener("webkitcurrentplaybacktargetiswirelesschanged", function(){ video.webkitCurrentPlaybackTargetIsWireless ? useNative() : useOverlay(); });
  }
  if("pictureInPictureEnabled" in document){
    video.addEventListener("enterpictureinpicture",useNative);
    video.addEventListener("leavepictureinpicture",useOverlay);
  }
  document.addEventListener("fullscreenchange", function(){
    var fs=document.fullscreenElement;
    if(!fs) return useOverlay();
    (fs===video || (fs && fs.contains && fs.contains(video))) ? useNative() : useOverlay();
  });
});
</script>
                <figcaption></figcaption></figure><div class="dr5emd-sublist"><details><summary>字幕一覧(クリック)</summary> <p>
1) 複数デバイスを取り込んだ動画づくり<br>
2) フルラインアップで録画をしています。<br>
3) 右上にWebカメラ。<br>
4) 中央から右寄りにiPad。<br>
5) 左上にiPhone。カメラを試しに映してみます。<br>
6) 左下にパペット。<br>
7) iPadを消すと、下にMacがあります。<br>
8) 例えば、フリーボードのアプリを表示してみます。<br>
9) 今の状態は、Macの画面、iPhone、Webカメラ、パペット、そこへiPadを上から重ねます。<br>
10) これでオールラインアップです。<br>
11) こんな感じで、合成、複合が出来ます。<br>
12) 非常に便利です。以上です。<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><script>
(function(){
  var root=document.querySelector(".dr5emd-sublist");
  var video=document.getElementById("myVideo");
  if(!root || !video) return;
  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;
  }
  root.addEventListener("click", function(e){
    var a=e.target.closest && e.target.closest("a.imk-cue[data-seek]");
    if(!a || !root.contains(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 listContainer = root.querySelector("details > p");
    if(!listContainer) return;
    var cues = listContainer.querySelectorAll("a.imk-cue");
    if(cues.length === 0) return;
    var cur = video.currentTime;
    var active = null;
    for(var i=0; i<cues.length; i++){
        var t = parseTs(cues[i].getAttribute("data-seek"));
        if(t !== null && cur >= t - 0.5){
            active = cues[i];
        } else if(t > cur){
            break;
        }
    }
    if(active){
        if(active.classList.contains("active-hl")) return;
        var old = listContainer.querySelectorAll(".active-hl");
        for(var k=0; k<old.length; k++) old[k].classList.remove("active-hl");
        active.classList.add("active-hl");
        if(listContainer.offsetParent !== null){
            var containerRect = listContainer.getBoundingClientRect();
            var activeRect = active.getBoundingClientRect();
            var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (active.clientHeight / 2);
            listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
        }
    }
  });
})();
</script>
                </div>

  <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>以前の<a href="https://imakat.com/2024/01/31/19696/" target="_blank">ブログ</a>では、有線接続の有用性について解説しました。その中で、一つの完成形として、Mac、iPad、iPhone、Webカメラなど複数デバイスを有線接続した方法について、紹介しました。これは、その実施動画です。接続方法は以下の通りです。</p>



<p>OBS Studioは、配信に使う以外にも、こうした動画作成にも、非常に役に立ちます。</p>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1bgQ_TvuwPJP_q_H0X_TqGbq0IcOAhUmfNve5cJBE_CE/edit?usp=sharing">
<img decoding="async" src="https://docs.google.com/drawings/d/1bgQ_TvuwPJP_q_H0X_TqGbq0IcOAhUmfNve5cJBE_CE/pub?w=960&#038;h=720"
></a>



<p>以上です。</p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=W0Bs5TVy.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=W0Bs5TVy.png" alt=""/></a></figure>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">23609</post-id>	</item>
		<item>
		<title>周辺機器の接続〜「近い」ものは有線。「遠い」ものは無線。それが電器屋の常識ではなかったのか</title>
		<link>https://imakat.com/2024/01/31/19696/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Wed, 31 Jan 2024 07:31:02 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[OBS]]></category>
		<category><![CDATA[USB-C]]></category>
		<category><![CDATA[MX ERGO]]></category>
		<category><![CDATA[拡張ディスプレイ]]></category>
		<category><![CDATA[CamX]]></category>
		<category><![CDATA[Thunderbolt]]></category>
		<category><![CDATA[HDMI]]></category>
		<category><![CDATA[スマホ新法]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=19696</guid>

					<description><![CDATA[25.10.19追記：25年12月施行のスマホ新法で、iPhoneからMacへのWiFiネットワーク経由のミラーリングやAirDropは、使えなくなるリスクが指摘されています。それと比べて、有線ケーブルによる接続は、はる [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>25.10.19追記：<br>25年12月施行のスマホ新法で、iPhoneからMacへのWiFiネットワーク経由のミラーリングやAirDropは、使えなくなるリスクが指摘されています。それと比べて、有線ケーブルによる接続は、はるかに排他性、独占性がなく使用不可になるリスクはほとんどないとされています。</p>



<p>25.6.25追記：<br>M2 Mac miniに、iPadを３つ目のディスプレイとして使う方法、を追記しました。</p>



<hr class="wp-block-separator has-text-color has-key-color-color has-alpha-channel-opacity has-key-color-background-color has-background is-style-default"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>WiFiは、固まったり寸断することがあります。また、今回は家の中にあるMacとiPadの繋げ方の改善なので、直接は関係ないですが、一般にスピードが不安定です。さらに、微弱ではありますが<span class="bold">電磁波の被曝</span>も生じます。</p>



<p>100Mも離れているがゆえ不安定なのは仕方ないとしても、今回MacとiPadはすぐ隣りに至近距離で置いてあるわけです。サブディスプレイとして使おうとしています。すぐ隣にありながら、不安定、繋がらない、繋ぎ方が難しい、それはどこかで聞いた人間関係のようで、よくある話といえばそんなものでしょうか。いえいえ、これは物理の問題。ヘンテコリンなことと感じます。</p>



<p>よく考えてみてください。お月様まで電線を結べますか？</p>



<p>基本的な考え方は、「遠い」は無線、「近い」は有線です。</p>



<p>というか、まずは、<strong>有線接続が基本</strong>です。</p>



<p>さて、よく知られているアップルの魅力として、アップル製品同士はなにも用意しなくても無線でサクッと繋がることにありました。しかし今回大事な発想は、一度アップル製品であることを忘れて、MacとiPadをケーブルで繋げる。ただそれだけのことをやってみます。</p>



<p><strong>2つの実現</strong></p>



<p>それは１つ目は、Macの映像をiPadで映すこと。2つ目は、iPadの映像をMacで映すことです。</p>



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



<h4 class="wp-block-heading">１　[1]の方法〜Macの映像を、iPadに表示する。</h4>



<p>第1は、iPad(iPadOS17.3)をMacの拡張ディスプレイにする方法です。（Macをミラーリングすることもできますが、Macの映像と同じものを小さいiPadの画面で見る意味は殆どありません。家の中では。）アップルがおすすめの方法はSideCarです。SideCarで有線接続に切り替えることもできますが、最初にWiFiで無線接続してからその後で有線に切り替えるやり方になります。これがなかなか厄介でして、<strong>SideCarは、Macを再起動した後に、そのまま有線接続が有効になってiPadの画面にMacが表示されるかというと、そうならない</strong>、<br>メニューバーの「画面ミラーリング」から接続する必要があります。ストレス！<br>設定を触っていると、BluetoothをONにしてくれ、WiFiをONにしてくれ、インターネットに接続してくれ、だのと、隣にあるものに対して、なんでそんなに色々必要なのかとイライラ、ストレス！<br><br>やっぱり、「<strong>ケーブルつなげてサクッ</strong>」といきたい。</p>



<p>以下の図をご覧ください。</p>



<p>今回、Macの「画面ミラーリング」は使わず、いきなりケーブルで接続します。</p>



<!--別ページ側の画像図形動画 -->
<a href="https://imakat.com/vm5?movid=909236498" target="_blank">
<!--投稿側の画像図形 -->
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vRtahZg1ZEOUYvPeUB_mSkM9AOoWueXrxvWgVOFVENwRN4bUJ2_Y3ZL4k2EU7iL7veIcvwUHep2NKBi/pub?w=960&amp;h=720">
</a>



<p>なお私はCamXアプリがシンプルでいいと選びましたがCamo Studioもいいと思います。</p>



<p>ただ残念ながら、このCamXアプリを使って、長時間、Macの拡張ディスプレイとして放置しておきますと、つまり常設すると、Macがだんだん重くなってきて、Macを再起動するということが時々あります。従って、この使い方は、一時的にiPadを代用する使い方になろうと感じます。</p>



<p>器具類やアプリなどを購入して時間を費して、あれこれ工夫するより、最近非常に安くなった単機能のモニターを購入して、直接、Macと接続するのもありだと考えます。iPadはiPad本来の使い方で活かす、ということでしょう。</p>



<!--別ページ側の画像図形動画 -->
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1ql2CZgfVNPG_az-G68NYRmuYaD0-yhgATu8kdQdQ708/edit?usp=sharing">
<!--投稿側の画像図形 -->
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vS12F2EioIAC9NWyEqpNWxQ1En2GkPnM7IjHA933DkuPqX87AeMrmgHQxsimq_p9cLwHwsDzYlMwpqV/pub?w=960&amp;h=720">
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



<h4 class="wp-block-heading">２　[2]の方法〜iPadの映像をMacで表示する。</h4>



<p>第2の方法、iPadをMacへ映すことですが、iPad miniやiPhoneの映像を拡大してみたい、さらにその映像を録画共有したい場合に使うことになります。これも有線接続なら無線接続より簡単です。Thunderboltケーブル(※1)を挿し込むだけです。あとはOBSやQuickTimePlayerからiPadを選択して表示します。</p>



<!—別ページ側の画像図形動画 httpsを挿入—>
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/12COFLYbMdoVegIwkErI1cCv6sKsna-HfqZA_lJWtRlc/edit?usp=sharing">
<!—投稿側の画像図形 httpsを挿入—>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vRhbfqqRC81v949KKC-t3RPt8OwmBmARa5YqNfX9hnr5hCNyu20R_TUIbrT4MTCv2G_sytXtr9_GMto/pub?w=960&amp;h=720"
>
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



<p><strong>突然、接続解除のストレス</strong></p>



<p>このThunderboltケーブル接続で、第1の拡張ディスプレイも兼用出来ないのか、つまりiPadの映像を→Macで表示、だけでなく逆方向のMacの映像を→iPadで表示、も使えないのか、ということですが、Mac設定の「画面ミラーリング」で「個別のディスプレイとして使用」を選択すれば、Macの映像を→iPadで表示、Macの拡張ディスプレイとして使えます。但し、iPadの映像を→Macで表示、Mac側からiPadの映像をキャプチャリングするアプリ(例えばOBSやQuickTimePlayerなど)を立ち上げると、「画面ミラーリング」の方法では、<strong>突然、接続解除</strong>になってしまいます。OBSの場合ですが、シーンの一つでiPadをキャプチャーするようにしてあって、ただしそのシーンを選択していない状態であっても、あるいはiPadを非表示にしても、接続解除されてしまいます。つまりOBSを何か別の使用目的で立ち上げても、そのOBSの設定のどこかにiPadキャプチャーが登録されていると、それに影響を受けて接続解除されるということですので、ストレスが大きいです。</p>



<p>日常は[1]の方法で使用するようにして、iPadの画面をMacの画面の中で録画したい、その時だけは[2]の接続に変える、そのように使用するしかありません。</p>



<p>※1 <a rel="noopener" target="_blank" href="https://hanpenblog.com/15679">Thunderbolt3と4があります<span class="fa fa-external-link external-icon anchor-icon"></span></a>。</p>



<h4 class="wp-block-heading">３　拡張ディスプレイは日常的に使える道具。</h4>



<p>第１の方法について、詳しく見てみます。<br>下図をご覧ください。拡張ディスプレイ用ケーブルを挿し込む→CamXアプリ(無料)を起動する、ただそれだけで、下図の状態になります。</p>



<p>このままの状態でiPadとしても拡張ディスプレイとしても両方使える点が素晴らしいです。マウスでiPadアプリの操作、Mac間のアプリの移動が行えます。マウスは手元でMac,iPadが切り替えられるタイプが非常に便利です。</p>



<!—別ページ側の画像図形動画 httpsを挿入—>
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1OmL1deeiSp3mec2ymk27vwTVqHeiC6z682GwFybkAlc/edit?usp=sharing">
<!—投稿側の画像図形 httpsを挿入—>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vR-_F0f7TFZVQvOB-pT0wPxuOaP5yMY2fCjT_6VA4GmDYCjVKosp6q-l_tDoKmrGPqHycpe_ipS591b/pub?w=960&#038;h=720"
>
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



<p>但し、iPadを拡張ディスプレイとして使った時の、解像度は、やはり純正の「画面ミラーリング」を使った方がクリアで見やすいです。</p>



<p>その感じに近づくように調整しましたが、2箇所あります。１つ目は、Mac側のシステム設定→ディスプレイ→拡張ディスプレイで、使用する解像度を1344&#215;1008にすること。２つ目は、iPadのCamX→画像設定でズームを35程度にすることです。</p>



<!—別ページ側の画像図形動画 httpsを挿入—>
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1-80UChi6tZCUdXFNItC0k13XkjFpGRE9jSX59f9MozM/edit?usp=sharing">
<!—投稿側の画像図形 httpsを挿入—>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vT932BQAwjgIs5XUY9Rph4MBzoTbSPt0CQin0v2l01jv5sYz549EvMtW_zkOIRBCsrrVZKPYBcNvfbe/pub?w=960&#038;h=720"
>
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



<h4 class="wp-block-heading">４　単機能モニターとiPadの両方使うスタイル。</h4>



<h5 class="wp-block-heading">その１</h5>



<p>単機能モニターの価格が安くなっており、16インチでも20,000円以下になっています。こうなってくるとアプリやケーブルに出費して設定に苦労するより、モニターを買ってしまった方が得策と感じます。実際、私の場合、単機能モニターとiPadを両方使うスタイルになっています。以下の方法ですと、iPadは通常は、独立して使用して、iPad,iPhoneの画面をMacに表示したいときは、Mac側でOBSやQuickTimePlayerを立ち上げて行います。</p>



<!—共有からリンクを知っている全員、閲覧者、と変更してリンクをコピー"https〜sharing"の位置にペースト—>
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1rIClFBbzpbfrEIyKYuvPOdi7TezY1sWZ7IIo-yDtxjI/edit?usp=sharing">
<!—埋め込みコードをペースト—>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vRONd5GMutcPmzrx-Avmc2tSUc1oCu7kRZ--BjU6riez-gjZwvA8yJ6k5T-sgNf0BoJSmty6AtJPGdS/pub?w=960&amp;h=720">
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



<p>さらにこの方法ですと、Windows RemoteでWindowsPCをMacから開いて、Windowsを単機能モニターに表示して操作することも出来ます。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=F9kKOr6m.jpg" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=F9kKOr6m.jpg" alt="" style="width:398px;height:auto"/></a><figcaption class="wp-element-caption">左にMac、右の単機能モニターへWindowsを表示。ブログの挙動を調べたりExcelを使ったりする。</figcaption></figure>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=zigBS8oe.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zigBS8oe.png" alt=""/></a><figcaption class="wp-element-caption">Macの拡張モニターに、OBSを表示してその中に、Macの主モニター、iPad、iPhone、パペット（カメラとマイクに反応)を配置した、いわばフル活用パターンです。</figcaption></figure>



<p>さらに、その後、改善したのが以下の状態です。<br></p>



<h6 class="wp-block-heading"><span class="bold-red">↓25.6.25追記</span></h6>



<h5 class="wp-block-heading">その２</h5>



<p>上の2の[2]で、Thunderboltケーブル接続１本で、双方向、つまり「MacをiPadへ映す＆iPadをMacへ映す」を実現できれば嬉しい。と書きましたが、Macの場合、Ethernetをインターネット利用では優先させながら、WiFiネットワークを稼働させることを今更発見しました。　ネットワーク設定の中の、右下をクリックして、「サービスの順序」において、Ethernet類を上の位置、Wi-Fiを下の位置に、配置すれば、両方接続済みの場合でも、インターネット接続はEthernet接続が優先されます。</p>



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



<p>通常、M2 Mac miniは、外部ディスプレイは2台まで可能なのですが、iPadを使うことにより、外部のアプリを使わず、純正の「画面ミラーリング」機能だけで、３台のディスプレイを映すことができるようになりました。ただし欠点としては、<strong>Amazon Video、NHK+(他にもあるかも知れない)は、視聴できないこと</strong>、動画類は他のアプリのキー操作でカクつくこと、などがあります。</p>



<p>時々、「接続が切れました」となりますが、数秒でつながり元の画面に戻ります。</p>



<p>普段は、iPadはiPadモードで使うのがベターです。</p>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/170KZmhlnD99NONST_JWjSedCu8BTUDQBhqzOJob1504/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vTDUTenGSfAnFDdMkISxwymQuR097bX-KOclgxYW9FUXsCO87cdrb6893xC-C1YwdcKjA6uuuQP42EM/pub?w=960&#038;h=720"
></a>



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



<h6 class="wp-block-heading"><span class="bold-red">↑25.6.25追記</span></h6>



<h4 class="wp-block-heading">　その他</h4>



<p>下写真は、二種類のケーブルです。</p>



<p>ご参考にどうぞ。</p>



<!—別ページ側の画像図形動画 httpsを挿入—>
<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1O6C1Ls4dYxY54xq9pCXDBI6dYNM878ZX2HcTAo3rqb8/edit?usp=sharing">
<!—投稿側の画像図形 httpsを挿入—>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vQ8sLR1RPglMh-RhOymbuINUhpViOhFn778iGJwZNnOHrkUocpKQGJs9mxZkZAvC0d2IOBZhaU44KAc/pub?w=960&#038;h=720"
>
<span class="fa fa-external-link external-icon anchor-icon"></span></a>



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