aboutsummaryrefslogtreecommitdiffstats
path: root/stella.js
diff options
context:
space:
mode:
Diffstat (limited to 'stella.js')
-rw-r--r--stella.js233
1 files changed, 219 insertions, 14 deletions
diff --git a/stella.js b/stella.js
index ad82531..f3c9dbd 100644
--- a/stella.js
+++ b/stella.js
@@ -39,12 +39,11 @@ let PLUGIN_INFO =
<name lang="ja">すてら</name>
<description>For Niconico/YouTube/Vimeo, Add control commands and information display(on status line).</description>
<description lang="ja">ニコニコ動画/YouTube/Vimeo 用。操作コマンドと情報表示(ステータスライン上に)追加します。</description>
- <version>0.32.7</version>
+ <version>0.33.0</version>
<author mail="anekos@snca.net" homepage="http://d.hatena.ne.jp/nokturnalmortum/">anekos</author>
<license>new BSD License (Please read the source code comments of this plugin)</license>
<license lang="ja">修正BSDライセンス (ソースコードのコメントを参照してください)</license>
<minVersion>2.0</minVersion>
- <maxVersion>3.0</maxVersion>
<updateURL>https://github.com/vimpr/vimperator-plugins/raw/master/stella.js</updateURL>
<detail><![CDATA[
== Commands ==
@@ -327,7 +326,7 @@ Thanks:
file.appendRelativePath(U.fixFilename(title) + ext);
if (file.exists())
- return U.echoerr('The file already exists! -> ' + file.path);
+ return U.echoError('The file already exists! -> ' + file.path);
file = makeFileURI(file);
@@ -381,11 +380,11 @@ Thanks:
// 上手い具合に秒数に直すよ
fromTimeCode: function (code, max) {
var m;
- if (max && (m = /^(-?\d+(?:\.\d)?)%/(code)))
+ if (max && (m = /^(-?\d+(?:\.\d)?)%/.exec(code)))
return Math.round(max * (parseFloat(m[1]) / 100));
- if (m = /^(([-+]?)\d+):(\d+)$/(code))
+ if (m = /^(([-+]?)\d+):(\d+)$/.exec(code))
return parseInt(m[1], 10) * 60 + (m[2] == '-' ? -1 : 1) * parseInt(m[3], 10);
- if (m = /^([-+]?\d+\.\d+)$/(code))
+ if (m = /^([-+]?\d+\.\d+)$/.exec(code))
return Math.round(parseFloat(m[1]) * 60);
return parseInt(code, 10);
},
@@ -827,6 +826,71 @@ Thanks:
// }}}
/*********************************************************************************
+ * VideoPlayer {{{
+ *********************************************************************************/
+
+ function VideoPlayer () {
+ Player.apply(this, arguments);
+ }
+
+ VideoPlayer.prototype = {
+ __proto__: Player.prototype,
+
+ functions: {
+ currentTime: 'rw',
+ fetch: '',
+ fileURL: '',
+ makeURL: '',
+ muted: 'rw',
+ pageinfo: '',
+ pause: 'x',
+ play: 'x',
+ playEx: 'x',
+ playOrPause: 'x',
+ relations: '',
+ title: '',
+ totalTime: 'r',
+ volume: 'rw',
+ quality: '',
+ qualities: ''
+ },
+
+ icon: 'TODO',
+
+ get currentTime () parseInt(this.player.currentTime),
+ set currentTime (value) (this.player.currentTime = value),
+
+ get muted () this.player.muted,
+ set muted (value) (this.player.muted = value),
+
+ get player ()
+ content.document.querySelector('video'),
+
+ get ready () !!this.player,
+
+ get state () {
+ if (this.player.ended)
+ return Player.ST_ENDED;
+ if (this.player.paused)
+ return Player.ST_PAUSED;
+ return Player.ST_PLAYING;
+ },
+
+ get totalTime () parseInt(this.player.duration),
+
+ get isValid () false,
+
+ get volume () parseInt(this.player.volume * 100),
+ set volume (value) (this.player.volume = value / 100),
+
+ play: function () this.player.play(),
+
+ pause: function () this.player.pause()
+ };
+
+ // }}}
+
+ /*********************************************************************************
* YouTubePlayer {{{
*********************************************************************************/
@@ -835,7 +899,7 @@ Thanks:
}
YouTubePlayer.getIDfromURL = function (url) let ([_, r] = url.match(/[?;&]v=([-\w]+)/)) r;
- YouTubePlayer.isVideoURL = function (url) /^https?:\/\/(www\.)?youtube\.com\/watch\?.+/(url);
+ YouTubePlayer.isVideoURL = function (url) /^https?:\/\/(www\.)?youtube\.com\/watch\?.+/.test(url);
YouTubePlayer.prototype = {
__proto__: Player.prototype,
@@ -923,11 +987,12 @@ Thanks:
let url = item.querySelector('a').href;
if (!YouTubePlayer.isVideoURL(url))
continue;
+ let id = YouTubePlayer.getIDfromURL(url);
result.push(
new RelatedID(
- YouTubePlayer.getIDfromURL(url),
+ id,
item.querySelector('span.title').textContent,
- item.querySelector('img').src
+ 'http://img.youtube.com/vi/' + id + '/1.jpg'
)
);
}
@@ -958,7 +1023,7 @@ Thanks:
get totalTime () parseInt(this.player.getDuration()),
- get isValid () U.currentURL.match(/^http:\/\/(?:[^.]+\.)?youtube\.com\/watch/),
+ get isValid () (this.player && U.currentURL.match(/^http:\/\/(?:[^.]+\.)?youtube\.com\/watch/)),
get volume () parseInt(this.player.getVolume()),
set volume (value) (this.player.setVolume(value), this.volume),
@@ -967,8 +1032,12 @@ Thanks:
// all(1080p,720p,480p,360p) -> 37, 22, 35, 34, 5
// FIXME 一番初めが最高画質だと期待
let cargs = content.wrappedJSObject.yt.config_.PLAYER_CONFIG.args;
- let url = decodeURIComponent(cargs.fmt_url_map.split(',')[0].split('|')[1]);
- U.download(url, filepath, '.flv', this.title);
+ cargs.url_encoded_fmt_stream_map.split(',')[0].split('&').forEach(function(x) {
+ let [key, val] = x.split('=');
+ if (key == 'url') {
+ U.download(decodeURIComponent(val), filepath, '.flv', this.title);
+ }
+ }, this);
},
makeURL: function (value, type) {
@@ -991,6 +1060,141 @@ Thanks:
// }}}
/*********************************************************************************
+ * YouTubePlayer5 {{{
+ *********************************************************************************/
+
+ function YouTubePlayer5 (stella) {
+ Player.apply(this, arguments);
+ this._player = new VideoPlayer(stella);
+ }
+
+ YouTubePlayer5.prototype = {
+ __proto__: YouTubePlayer.prototype,
+
+ functions: {
+ currentTime: 'rw',
+ fetch: 'x',
+ fileURL: 'r',
+ makeURL: 'x',
+ muted: 'rwt',
+ pageinfo: 'r',
+ pause: 'x',
+ play: 'x',
+ playEx: 'x',
+ playOrPause: 'x',
+ relations: 'r',
+ title: 'r',
+ totalTime: 'r',
+ volume: 'rw',
+ quality: 'rw',
+ qualities: 'r'
+ },
+
+ icon: 'http://www.youtube.com/favicon.ico#hoge',
+
+ get fileExtension () '.mp4',
+
+ get fileURL ()
+ let (as = content.document.defaultView.wrappedJSObject.swfArgs)
+ ('http://www.youtube.com/get_video?fmt=22&video_id=' + as.video_id + '&t=' + as.t),
+
+ get id ()
+ YouTubePlayer.getIDfromURL(U.currentURL),
+
+ get pageinfo () {
+ let doc = content.document;
+ let desc = doc.querySelector('#eow-description');
+ return [
+ [
+ 'comment',
+ desc ? desc.textContent.trim() : ''
+ ],
+ [
+ 'tags',
+ XMLList([
+ <span>[<a href={v.href}>{v.textContent}</a>]</span>
+ for ([, v] in Iterator(doc.querySelectorAll('#eow-tags > li > a')))
+ ].join(''))
+ ],
+ [
+ 'quality',
+ this.quality
+ ]
+ ];
+ },
+
+ get player () this._player,
+
+ get quality () this.player.getPlaybackQuality(),
+ set quality (value) this.player.setPlaybackQuality(value),
+
+ get qualities () this.player.getAvailableQualityLevels(),
+
+ get ready () !!this.player,
+
+ get relations () {
+ let result = [];
+ let doc = content.document;
+ for each (let item in Array.slice(doc.querySelectorAll('#watch-tags > div > a'))) {
+ result.push(new RelatedTag(item.textContent));
+ }
+ for each (let item in Array.slice(doc.querySelectorAll('.video-list-item'))) {
+ let url = item.querySelector('a').href;
+ if (!YouTubePlayer.isVideoURL(url))
+ continue;
+ let id = YouTubePlayer.getIDfromURL(url);
+ result.push(
+ new RelatedID(
+ id,
+ item.querySelector('span.title').textContent,
+ 'http://img.youtube.com/vi/' + id + '/1.jpg'
+ )
+ );
+ }
+ return result;
+ },
+
+ get title ()
+ content.document.title.replace(/^YouTube - /, ''),
+
+ fetch: function (filepath) {
+ // all(1080p,720p,480p,360p) -> 37, 22, 35, 34, 5
+ // FIXME 一番初めが最高画質だと期待
+ let cargs = content.wrappedJSObject.yt.config_.PLAYER_CONFIG.args;
+ cargs.url_encoded_fmt_stream_map.split(',')[0].split('&').forEach(function(x) {
+ let [key, val] = x.split('=');
+ if (key == 'url') {
+ U.download(decodeURIComponent(val), filepath, '.flv', this.title);
+ }
+ }, this);
+ },
+
+ makeURL: function (value, type) {
+ switch (type) {
+ case Player.URL_ID:
+ return 'http://www.youtube.com/watch?v=' + value;
+ case Player.URL_TAG:
+ return 'http://www.youtube.com/results?search=tag&search_query=' + encodeURIComponent(value);
+ case Player.URL_SEARCH:
+ return 'http://www.youtube.com/results?search_query=' + encodeURIComponent(value);
+ }
+ return value;
+ },
+ };
+
+ 'play pause currentTime muted state totalTime volume'.split(/\s+/).forEach(function (name) {
+ let getter = VideoPlayer.prototype.__lookupGetter__(name);
+ let setter = VideoPlayer.prototype.__lookupSetter__(name);
+ let value = !(getter || setter);
+ if (getter || value)
+ YouTubePlayer5.prototype.__defineGetter__(name, function () this.player[name]);
+ if (setter || value)
+ YouTubePlayer5.prototype.__defineSetter__(name, function (value) (this.player[name] = value));
+ });
+
+ // }}}
+
+ /*********************************************************************************
* YouTubeUserChannelPlayer {{{
*********************************************************************************/
@@ -999,7 +1203,7 @@ Thanks:
}
YouTubeUserChannelPlayer.getIDfromURL = function (url) let ([_, r] = url.match(/\/([^\/]+)($|[\?]+)/)) r;
- YouTubeUserChannelPlayer.isVideoURL = function (url) /^https?:\/\/(www\.)?youtube\.com\/watch\?.+/(url);
+ YouTubeUserChannelPlayer.isVideoURL = function (url) /^https?:\/\/(www\.)?youtube\.com\/watch\?.+/.test(url);
YouTubeUserChannelPlayer.prototype = {
__proto__: YouTubePlayer.prototype,
@@ -1657,6 +1861,7 @@ Thanks:
this.players = {
niconico: new NicoPlayer(this.stella),
youtube: new YouTubePlayer(this.stella),
+ youtube5: new YouTubePlayer5(this.stella),
youtubeuc: new YouTubeUserChannelPlayer(this.stella),
vimeo: new VimeoPlayer(this.stella)
};
@@ -1798,7 +2003,7 @@ Thanks:
return U.raiseNotSupportedPage();
let arg = args.literalArg;
- let index = (/^\d+:/)(arg) && parseInt(arg, 10);
+ let index = /^\d+:/.test(arg) && parseInt(arg, 10);
if (index > 0)
arg = lastCompletions[index - 1].command;
let url = self.player.has('makeURL', 'x') ? makeRelationURL(self.player, arg) : arg;