aboutsummaryrefslogtreecommitdiffstats
path: root/nico_related_videos.js
blob: 40700ec639febfc090bc7bfba1f9126123642780 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// ==VimperatorPlugin==
// @name           Nico Related Videos
// @description-ja ニコニコ動画のオススメ動画のリスト
// @license        Creative Commons 2.1 (Attribution + Share Alike)
// @version        1.3.0
// ==/VimperatorPlugin==
//
//  Author:
//    anekos
//
//  Usage:
//    ニコニコ動画のオススメ動画のリストを補完で表示します。
//
//    コマンドにURL以外を指定したときの動作:
//      空            => ニコニコ動画のトップページに移動
//      動画ID(sm.+)  => 動画に移動
//      ":" タグ名    => タグ検索
//      その他文字列  => ニコニコ動画でそれを検索
//
//    "!" をつけると新しいタブで開く。
//
// Link:
//    http://d.hatena.ne.jp/nokturnalmortum/20080910#1220991278


(function () {

  function getVideoId () {
    let m = buffer.URL.match(/^http:\/\/(?:tw|es|de|www)\.nicovideo\.jp\/watch\/([a-z0-9]+)/);
    return m && m[1];
  }

  function httpRequest (uri, onComplete) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200)
          onComplete(xhr.responseXML);
        else
          throw new Error(xhr.statusText)
      }
    };
    xhr.open('GET', uri, true);
    xhr.send(null);
  }

  function getRelatedVideos () {
    let videoId = getVideoId();
    if (!videoId)
      return [];
    let videos = [];
    let uri = 'http://www.nicovideo.jp/api/getrelation?sort=p&order=d&video=' + videoId;
    let xhr = new XMLHttpRequest();
    xhr.open('GET', uri, false);
    xhr.send(null);
    let xml = xhr.responseXML;
    let v, vs = xml.evaluate('//video', xml, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE , null);
    while (v = vs.iterateNext()) {
      let [cs, video] = [v.childNodes, {}];
      for each (let c in cs)
        if (c.nodeName != '#text')
          video[c.nodeName] = c.textContent;
      videos.push(video);
    }
    return videos;
  }

  function getRelatedTags () {
    let doc = content.document;
    let nodes = doc.getElementsByClassName('nicopedia');
    return [it.textContent for each (it in nodes) if (it.rel == 'tag')];
  }


  let last = {url: null, completions: []};
  let nothing = 'No related videos';

  commands.addUserCommand(
    ['nicorelated'],
    'niconico related videos',
    function (url, bang) {
      (url.string === undefined) || (url = url.string);
      url = (function () {
        if (url == nothing)
          return 'http://www.nicovideo.jp/';
        if (url.match(/^[a-z]{2}\d+$/))
          return 'http://www.nicovideo.jp/watch/' + url;
        if (url.match(/^[:\uff1a]/))
          return 'http://www.nicovideo.jp/tag/' + encodeURIComponent(url.substr(1));
        if (url.indexOf('http://') == -1)
          return 'http://www.nicovideo.jp/search/' + encodeURIComponent(url);
      })() || url;
      liberator.open(url, bang ? liberator.NEW_TAB : liberator.CURRENT_TAB);
    },
    {
      bang: true,
      completer: function (context, arg, bang) {
        if ((buffer.URL != last.url) || !last.completions.length) {
          last.completions = [];
          getRelatedVideos().forEach(function (it) last.completions.push([it.url, it.title]));
          getRelatedTags().forEach(function (it) last.completions.push([":" + it, "tag"]));
          last.url = buffer.URL;
        }
        context.title = ['Keyword'];
        context.completions = last.completions;
      }
    },
    true
  );

})();