Hexoのプラグインをカスタマイズする2

04/21

JSが動いてないことに気づく

目次

経緯

いつの頃からかYouTubeなどの動画埋め込みの自動再生がされなくなっていた。
恐らくhexo-tag-owlを再インストールしたからだなと。
てことで、もう一度改修する。

要件

まずは改修する要件を明確にする。

  • youtube埋め込みコードの自動生成
  • niconico埋め込みコードの自動生成
  • dailymotion埋め込みコードの自動生成
  • imdbの映画情報タグの自動生成

以上の改修をhexo-tag-owlに対して行う。
そしてさらにyoutube、niconico、dailymotionのエレメントに
jqueryのinviewイベントをトリガーに自動再生を行う。

modified file list

  1. hexo-tag-owl/lib/tag/index.js
  2. hexo-tag-owl/lib/tag/images/imdb.js1
  3. hexo-tag-owl/lib/tag/videos/niconico.js
  4. hexo-tag-owl/lib/tag/videos/nicovideo.js1
  5. hexo-tag-owl/lib/tag/videos/dailymotion.js1
  6. hexo-tag-owl/lib/tag/videos/youtube.js

index.js

index.js

use strict';

/**
 *  tag list
**/
// tag list
var list = {
  videos: {
    path: ['.', 'videos'],
    tags: ['youtube', 'nicovideo', 'niconico', 'bilibili', 'vimeo', 'tudou', 'youku', 'tencent', 'ted', 'dailymotion']
  },
  images: {
    path: ['.', 'images'],
    tags: ['local', 'giphy', 'imdb']
  }
};

// selector for recording a lot of videos and images tags
var selector = {};
Object.keys(list).forEach(function (type) {
  var path = list[type].path.join('/');
  list[type].tags.forEach(function (tag) {
    selector[tag] = require(path + '/' + tag);
  })
});

module.exports = selector;

imdb.js

imdb.js

'use strict';

const cheerio=require('cheerio-httpcli');

module.exports = (hexo, args) => {
    /* search */
    let q=args[1];
    let title=((q)=>{
        let titleArray=q.split(" ");
        let searchTitle="";
        for(let i=0;i<titleArray.length;i++){
            (i!=titleArray.length-1)?searchTitle+=titleArray[i]+'+':searchTitle+=titleArray[i];
        }
        return searchTitle;
    })(q);
    let movies=[];
    let searchurl='https://www.imdb.com/find';
    let searchoptions={
        s: 'tt',
        ttype: 'ft',
        ref_: 'fn_ft',
        q: title,
    };
    const result=cheerio.fetchSync(searchurl, searchoptions);
    if(result.error)
        return '<div class="owl-media owl-image owl-imdb"><img src="/assets/no-media.png" alt="no media"></div>';
    let $=result.$;
    $('.findResult').each(async (i, element)=>{
        const $image = $(element).find('td a img');
        const $title = $(element).find('td.result_text a');
        const imdbID = $title.attr('href').match(/title\/(.*)\//)[1];
        const movie = {
            image: $image.attr('src'),
            title: $title.text(),
            imdbID : imdbID
        };
        movies.push(movie);
        return false;
    });

    /* details */
    let detailurl='https://www.imdb.com/title/'+movies[0].imdbID+'/';
    let detailoptions={
        ref_:'fn_al_tt_1',
    };
    const result2=cheerio.fetchSync(detailurl, detailoptions);
    if(result2.error)
        return '<div class="owl-media owl-image owl-imdb"><img src="/assets/no-media.png" alt="no media"></div>';
    $=result2.$;
    var articleChildren = $('.subtext').children()
    var movieDetails = {
        title : $('.title_wrapper h1').text(),
        year: $('#titleYear a').text(),
        rating : $('.ratingValue strong span').text(),
        votes : $('.imdbRating a span').text(),
        time : $('.subtext time').text().trim(),
        poster : $('.poster a img').attr('src'),
        release : $(articleChildren[7]).text().trim(),
        story : $('.article .canwrap p span').text().trim(),
        writtenBy : $('.article .canwrap em a').text()
    }
    return '<div class="owl-media owl-image owl-imdb"><img src="'+movieDetails.poster+'" alt="'+movieDetails.title+'"><div class="imdb-staff"><ul><li>Title: '+movieDetails.title+'</li><li>Release Date: '+movieDetails.release+'</li></ul></div></div>';
}

niconico.js

niconico.js

'use strict';

var config = require('./config');
// niconico
module.exports = function (hexo, args) {
  var id   = args[0],
      type = args[1] || 'thumb',
      res  = '';
  if ('thumb' === type) {
    // thumb
    res += '<div class="owl-media owl-video owl-niconico niconico-thumb"><iframe src="//ext.nicovideo.jp/thumb/' + id + '" scrolling="no" ' + config.iframe + '></iframe></div>';
  }
  else {
    // watch
    res += '<div class="niconico-video owl-media owl-video owl-niconico niconico-watch" data-video-id="'+id+'"><div class="movie-wrap" data-video-id="'+id+'"></div></div>';
  }
  return res;
}

nicovideos.js

これはタグ名をすぐ忘れるので作っただけ。

{% owl niconico sm9999999 watch %}
{% owl nicovideo sm9999999 watch %}

どっちの書き方が合っているかうろ覚えだったので、だったらどっちも書けるようにしただけ。
niconico.jsをコピーしただけ。

dailymotion.js

dailymotion.js

'use strict';

var config = require('./config');
// dailymotion
module.exports = function (hexo, args) {
  var id = args[0];
  return '<div class="owl-media owl-video owl-dailymotion"><div class="dmplayer" dailyid="'+id+'" playoption="off"></div></div>';
}

youtube.js

youtube.js

'use strict';

var config = require('./config');
// youtube 9:16
module.exports = function (hexo, args) {
  var id = args[0];
  return '<div class="owl-media owl-video owl-youtube"><div class="movie-wrap"><div id="yt__'+id+'" class="youtube-video" width="854" height="480" data-video-id="'+id+'"></div></div></div>';
}

ここまででプラグインの改修は終わり。
次はView側を手をつける。

CSS

hexoはmain.cssを使っているので見た目を変えていく。
やったことはレスポンシブ対応のため

<div class="owl-video">
  <div class="movie-wrap">
    <iframe/>
  </div>
</div>

こんな構造としてiframeは常に100%の大きさで、movie-wrapクラスのdivエレメントでは大きさを考慮してパディングを確保、親のdivエレメントで最大の大きさを調整って感じ。
やったことはこんな感じ。

main.css

@media (min-width:1099px){
    .owl-video {
        max-width: 800px;
        margin: 0 auto;
    }
}
@media (max-width:1099px) {
    .owl-video {
        max-width: 600px;
        margin: 0 auto;
    }
}

.movie-wrap {
    position: relative;
    padding-bottom: 56.25%;
    height: 0;
    overflow: hidden;
}
.movie-wrap iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

JavaScript

先のタグの構造を実現するために以下を行っている。
YouTubeはjquery.youtube-inview-autoplay.jsで実現しているので、ここではniconicoとDailymotionだけ実現している。

main.js

$(document).ready(function(){
    $("div.niconico-video div.movie-wrap").each((i, _div)=>{
        $.when(
            $('<iframe>').attr({
                src: nicosrc+'/watch/' + $(_div).attr("data-video-id") + '?jsapi=1&playerId=' + i,
                id: 'nicovideoPlayer-' + i,
                frameborder: 0,
                allowfullscreen: '',
                width: '100%',
                height: '100%'
            }).appendTo($(_div))
        ).done((obj)=>{
            nicoPlayer.push(obj[0]);
            $(obj[0]).on('inview', function(event, isInView) {
                if (isInView) {
                    // element is now visible in the viewport
                    nicoPostMessage(event.target.id,
                    {
                        sourceConnectorType: 1,
                        eventName: 'play'
                    });
                    $("#nowplaying-img>img").attr('src', obj[0].thumbnail_url);
                    $("#nowplaying-product-title").text(obj[0].title);
                    $("#nowplaying-product-author").text('');
                } else {
                    // element has gone out of viewport
                    nicoPostMessage(event.target.id,
                    {
                        sourceConnectorType: 1,
                        eventName: 'pause'
                    });
                    $('#nowplaying-product-title').text(nowPlayingTitle);
                    $('#nowplaying-img>img').attr('src',nowPlayingImageUrl);
                    $('#nowplaying-product-author').text(nowPlayingAuthor);
                }
            });
        }).fail();
    });
    
    window.addEventListener('message', (e) => {
        if (e.origin !== nicosrc) return;
        if (nicoPlay === undefined) nicoPlay=0;
        if (e.data.playerId === nicoPlay) {
            const { data } = e.data;
            switch (e.data.eventName) {
            case 'playerMetadataChange': {
                nicoPlayerMetadataChange(data);
                break;
            }
            case 'playerStatusChange': {
                nicoPlayerStatusChange(data);
                break;
            }
            case 'loadComplete': {
                nicoRenderInfoTable(data.videoInfo);
                break;
            }
            default:
                console.log(e.data);
            }
            nicoPlaying = Object.assign({}, nicoPlaying, data);
        }
    });
    
    $('.dmplayer').each((i, _div)=>{
        $.when(
            $(_div).wrap(
                $('<div>').attr({
                    class: 'movie-wrap'
                })
            )
        ).done((obj)=>{
            $(_div).attr('id','dmplayer-'+i);
            let videoid=$(_div).attr('dailyid');
            let isautoplay=($(_div).attr('playoption')=="on")?true:false;
            let player=DM.player(_div, {
                video: videoid,
                width: "100%",
                height: "100%",
                params: {
                    autoplay: isautoplay,
                    mute: false
                }
            });
            player.load();
            dmPlayer.push(player);
            $('#dmplayer-'+i).on('inview', (event, isInView)=>{
                if (isInView) {
                    // element is now visible in the viewport
                    player.play();
                    $('#nowplaying-product-title').text(player.video.title);
                    $('#nowplaying-img>img').attr('src',player.video.thumbnail_url);
                    $('#nowplaying-product-author').text('');
                } else {
                    // element has gone out of viewport
                    player.pause();
                    $('#nowplaying-product-title').text(nowPlayingTitle);
                    $('#nowplaying-img>img').attr('src',nowPlayingImageUrl);
                    $('#nowplaying-product-author').text(nowPlayingAuthor);
                }
            });
            $('#dmplayer-'+i).attr('height','400');
        }).fail();
    });
});

では、これでやってみる。

Leeeettttt’s do it again

$ cd $HEXO_HOME
$ cd node_modules/hexo-tag-owl
$ npm i cheerio-httpcli --save
$ cd ../..
$ rm db.json
$ hexo g

$HEXO_HOMEは適宜読み替えていただきたい。
これでやりたいことはできた。
うれしい。


  1. 1.新規作成

コメント: