<?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>MAM | imakat.com</title>
	<atom:link href="https://imakat.com/tag/mam/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Sat, 13 Jun 2026 05:43:09 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</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>MAM | 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>第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[Dropbox]]></category>
		<category><![CDATA[MAM]]></category>
		<category><![CDATA[メディアアセット]]></category>
		<category><![CDATA[Mac]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=25796</guid>

					<description><![CDATA[メディアライブラリを作ろう ポイント解説： 作成するスクリプトは、結構、分量があります。ChatGPTを使い、ゆっくり進めるのがいいです。以下のスクリプトをChatGPTへコピペして、（１）「このスクリプトの解説をしてく [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">メディアライブラリを作ろう</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; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @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=46" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=kmelubbx.png" playsinline preload="none" 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><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></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

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

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) 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;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      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 = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          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";
          }

          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 ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "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){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        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 ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

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

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

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

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

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

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    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 class="wp-block-paragraph">作成するスクリプトは、結構、分量があります。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;＜マイライブラリ生成更新処理＞<br>このGoogle Apps Scriptは、WordPressと連携するメディアライブラリの自動管理システムです。Webhook (`doPost`) を介して新しいメディア情報の追加や既存パスの変更通知を受け取ります。 主要機能は以下の通りです。 1. **メディア情報の一元管理**: Googleスプレッドシート（F1シート）を主データソースとし、Dropboxリンク、ファイルパス、WordPress用のURL（正規化・エンコード済み）、ユニークID（wpidex）などを自動生成・更新します。 2. **パス変更履歴の適用**: ファイルパス変更履歴シート（F3シート）を利用し、F1シートの旧パスを新パスへ自動更新します。 3. **JSONファイルの生成と同期**: F1シートのデータからWordPress連携用のJSONファイル (`dropbox_wp_library.json`) をGoogle Driveに生成・上書き保存します。 4. **動画埋め込みJSONの更新**: 別シートの動画埋め込みデータをJSON化し、外部サーバー（Xserver）へ送信して`videoembed.json`を更新します。 5. **シートの整理と重複除去**: F1シートの不要行削除、K列フラグのリセット、重複行の整理（新しい方を優先し、一部データを引き継ぐ）、更新日時順での並べ替えを行います。 6. **pCloudID連携**: F1シートの情報に基づき、pCloudID同期用シートの内容を更新し、変更があった場合は更新フラグを立てます。 `processWorkingRecord`関数が中心的な役割を担い、モードに応じた一連の処理とデータ同期を安全に実行します。多岐にわたるユーティリティ関数が処理を支援します。</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 class="wp-block-paragraph"></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><tr><td colspan="2">&lt;dropboxリンクの定期的自動修復&gt;<br>このシステムはmacOS上でDropbox共有リンクの自動巡回・修復、およびリンクの有効性チェックを行うものです。`fix_dropbox_links.py`はスプレッドシートのローカルパスを基に、共有リンクをダウンロード可能な形式(raw=1)に変換し、Mac特有の濁点問題を修正してAPI経由で最新リンクを取得します。差分があればスプレッドシートを更新しフラグを立てます。この処理は`com.XXXXXX.fix_dropbox_links.plist`により1時間ごとに自動実行されます。さらに今回追加された`check_dropbox_link.py`は、任意のDropbox共有リンクが有効か（リンク切れしていないか）をAPIを用いて直接確認し、結果をログに出力します。これらのスクリプト群により、Dropbox共有リンクの継続的な整合性維持と異常検知を自動化、手動介入を減らした堅牢な運用を実現しています。<br></td></tr><tr><td colspan="2"><a href="https://imakat.com/script_list/?pubtxt=dropboxリンクの定期的自動修復_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 class="wp-block-paragraph">上の処理は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 class="wp-block-paragraph"><strong>第3章では、「<strong>YouTube（大手）に依存しないで配信する</strong>」</strong>についてご紹介します。<br></p>



<p class="wp-block-paragraph">&#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 wp-block-paragraph"><a href="https://imakat.com/media_library1" target="_blank">&#x1f517; 目次ページへ戻る</a></p>



<p class="wp-block-paragraph"></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[Mac]]></category>
		<category><![CDATA[Dropbox]]></category>
		<category><![CDATA[MAM]]></category>
		<category><![CDATA[メディアアセット]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=25693</guid>

					<description><![CDATA[メディアライブラリを作ろう はじめに： いまの時代、動画はたくさん出回っています。でも、その動画を作るために使った素材――たとえば写真や音声、字幕や説明文など――は、紐づいて保存されているでしょうか。 最近の動画編集ツー [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">メディアライブラリを作ろう</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; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @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=45" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=SNebSNKN.png" playsinline preload="none" 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" default></video></div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

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

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) 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;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      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 = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          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";
          }

          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 ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "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){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        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 ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

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

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

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

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

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

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

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



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



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



<p class="wp-block-paragraph">時代は生成AIですね。</p>



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



<p class="wp-block-paragraph"></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 class="wp-block-paragraph">さて、これからの時代、動画などのメディアコンテンツの作り方は、どんな考え方に傾いていくでしょうか。</p>



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



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



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



<p class="wp-block-paragraph">前者は、何が原因でどういう条件でこの結果となったかが分からないので、何を大事に残したらいいかが分からない。素材軽視、意外性重視、偶然好み、結果だけあればいい。完成物だけ持って飛び出していく人。やりっぱなしで、でも元ネタはここにあるはず、となると捨てられず、家はゴミ屋敷。</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 class="wp-block-paragraph">いいえ全員そうだとは言いませんが、概してそう。</p>



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



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



<p class="wp-block-paragraph"></p>



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



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



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



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



<p class="wp-block-paragraph">具体的に私の例で言うと、</p>



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



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



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



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



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



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



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



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



<p class="wp-block-paragraph">でも、どれも難しいプログラミングではなく、<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 class="wp-block-paragraph">そんな方にとって、きっとヒントになるシリーズになると思います。</p>



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



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



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



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



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



<p class="wp-block-paragraph">&#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 wp-block-paragraph"><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>
	</channel>
</rss>
