[Adobe] PremiereProCCで使えるジャンプチャプターエクステンション

#Premiereを使ってる全Youtuberへ
youtubeで動画を見ると、親切なチャンネルは概要欄にジャンプチャプターという物（勝手に呼称しています）を付けてくれる。
概要欄に書かれているタイムコードをクリックすると、その再生時間に飛べるって機能
こんな感じなもの↓

![コメント 2020-01-01 092520.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178061/3d3e60ac-7e12-ca23-3279-57df85ec3a4e.jpeg)

これを手作業で作るとそこそこ大変。
って事でPremiereのエクステンションを作りました。
![thumbnail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178061/71734e01-8e1a-8f3e-fe99-4b483373270b.jpeg)
まずはyoutubeで動画をご覧ください。


https://www.youtube.com/watch?v=NTkEtWW79gw

#今回のプログラムの考え方
内容はとてもシンプル。
単純にPremiereのマーカー情報を取得して、テキスト表示させているだけ。

###まずはメインとなるJsxから紹介

```jsx
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global $, Folder*/

var str = "If you need help go to my youtube channel"+"\r"+"https://www.youtube.com/channel/UCy6tHV_d458fg2VwKp5HGHQ";

function getMarker(){
    //マーカー情報
    var numMarkers = app.project.activeSequence.markers.numMarkers;
    var markers = app.project.activeSequence.markers;
    var markAry = [];
    var currentMarker;

    for(i=0;i<numMarkers;i++){
        if(i==0){
            currentMarker = markers.getFirstMarker();
            markerst = Math.floor(currentMarker.start.seconds);
            markAry.push("#"+(i+1)+":"+currentMarker.name+" "+toHms(markerst));
        }
        if(i>0){
            currentMarker = markers.getNextMarker(currentMarker);
            markerst = Math.floor(currentMarker.start.seconds);
            markAry.push("#"+(i+1)+":"+currentMarker.name+" "+toHms(markerst));
        }
    }

    if (markAry.length > 0){
        return markAry.join("\r");
    }else{
        alert("Please set a sequence marker")
        return str;
    }
}



function toHms(t) {
    var hms = "";
    var h = t / 3600 | 0;
    var m = t % 3600 / 60 | 0;
    var s = t % 60;

    if (h != 0) {
        hms = padZero(h) + ":" + padZero(m) + ":" + padZero(s) ;
    } else if (m != 0) {
        hms = padZero(m)+ ":" + padZero(s) ;
    } else {
        hms = padZero(m)+":"+padZero(s);
    }

    return hms;

    function padZero(v) {
        if (v < 10) {
            return "0" + v;
        } else {
            return v;
        }
    }
}
```

###次にextensionでフロントと繋ぐmain.js

```js
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global $, window, location, CSInterface, SystemPath, themeManager*/

(function () {
    'use strict';
    var outputArea = $('#output_area');
    var csInterface = new CSInterface();
    
    
    function init() {
                
        themeManager.init();
                
        $("#btn_test").click(function () {
            csInterface.evalScript(
             'getMarker()', function(x){outputArea.val(x)}
            );
        });
        
    }
        
    init();

}());
    

```

###次にフロントのindex.html

```html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
        
<link rel="stylesheet" href="css/topcoat-desktop-dark.min.css"/>
<link  id="hostStyle" rel="stylesheet" href="css/styles.css"/>

<title>Jump Chapter Generator</title>
</head>

<body class="hostElt">

    <div id="content">     
        <div id="signature" class="hostFontSize">
            script written by timetoedit
        </div>

        <div>                
            <button id="btn_test" class="topcoat-button--large hostFontSize">Jump Chapter Generate</button>                
        </div> 
        <br/>
        <div>                
        </div>
            <textarea id="output_area"></textarea>
        </div> 
    
    </div>
    
    <script src="js/libs/CSInterface.js"></script>
    <script src="js/libs/jquery-2.0.2.min.js"></script>
    <script src="js/themeManager.js"></script>
    <script src="js/main.js"></script>

</body>
</html>
```

###css

```css
/*Your styles*/

html {
    height: 100%;
    margin:10px;
}

body {
    margin: 10px;
    height:100%;
}


#content {
    margin-right:auto;
    margin-left:auto;
    vertical-align:middle;
    width:100%;
    height:100%;
}


#btn_test{
    width: 100%;
}
#output_area{
    width: 100%;
    height: 60%;
    resize: none;
}

#signature{
    margin: 0;
    margin-bottom:20px;
}

.picture{
     width: 30px;
    height: auto;  /* ←縦横比を維持する高さを自動計算 */   
    vertical-align:middle;
}


/*
Those classes will be edited at runtime with values specified
by the settings of the CC application
*/
.hostFontColor{}
.hostFontFamily{}
.hostFontSize{}

/*font family, color and size*/
.hostFont{}
/*background color*/
.hostBgd{}
/*lighter background color*/
.hostBgdLight{}
/*darker background color*/
.hostBgdDark{}
/*background color and font*/
.hostElt{}


.hostButton{
    border:1px solid;
    border-radius:2px;
    height:20px;
    vertical-align:bottom;
    font-family:inherit;
    color:inherit;
    font-size:inherit;
}
```

とまあこんな感じです。

#初めてのextension作成で悩んだとこ
それはmain.jsからhostscriptへ実行命令を出し、その返り値をどう受け取るかの部分でした。
部分で言うと

```jsx
csInterface.evalScript(
             'getMarker()', function(x){outputArea.val(x)}
            );
```
この部分
csInterface.evalScript('getMarker()',function(x){outputArea.val(x)});
このfunction(x){outputArea.val(x)ってのがちょっと理解出来ていませんでした。

Extensionもしっかり作れるように勉強せねばなりませんね・・・


##ちな、ミリ秒も取得するやつ

```jsx


function sec2time(timeInSeconds) {
    var pad = function(num, size) { return ('000' + num).slice(size * -1); },
    time = parseFloat(timeInSeconds).toFixed(3),
    hours = Math.floor(time / 60 / 60),
    minutes = Math.floor(time / 60) % 60,
    seconds = Math.floor(time - minutes * 60),
    milliseconds = time.slice(-3);

    return pad(hours, 2) + ':' + pad(minutes, 2) + ':' + pad(seconds, 2) + ',' + pad(milliseconds, 3);
}


var str = "If you need help go to my youtube channel"+"\r"+"https://www.youtube.com/channel/UCy6tHV_d458fg2VwKp5HGHQ";

function getMarker(){
    //マーカー情報
    var numMarkers = app.project.activeSequence.markers.numMarkers;
    var markers = app.project.activeSequence.markers;
    var markAry = [];
    var currentMarker;

    for(i=0;i<numMarkers;i++){
        if(i==0){
            currentMarker = markers.getFirstMarker();
            markerst = currentMarker.start.seconds;
            markAry.push("#"+(i+1)+":"+currentMarker.name+" "+sec2time(markerst));
        }
        if(i>0){
            currentMarker = markers.getNextMarker(currentMarker);
            markerst = currentMarker.start.seconds;
            markAry.push("#"+(i+1)+":"+currentMarker.name+" "+sec2time(markerst));
        }
    }

    if (markAry.length > 0){
        return markAry.join("\r");
    }else{
        alert("Please set a sequence marker")
        return str;
    }
}

getMarker()

```