pig-media-server 0.3.2 → 2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/bin/pig-media-server +4 -1
  4. data/gulpfile.js +33 -0
  5. data/javascripts/application.js +117 -0
  6. data/javascripts/chromecast.js +57 -0
  7. data/javascripts/components/head.js +106 -0
  8. data/javascripts/components/list.js +104 -0
  9. data/javascripts/components/new_flag.js +23 -0
  10. data/javascripts/components/player.js +171 -0
  11. data/javascripts/components/query_list.js +68 -0
  12. data/javascripts/components/sort.js +64 -0
  13. data/javascripts/components/watch.js +48 -0
  14. data/javascripts/controller.js +62 -0
  15. data/javascripts/custom_list.js +14 -0
  16. data/javascripts/event_dispatcher.js +21 -0
  17. data/javascripts/recent.js +34 -0
  18. data/javascripts/utils.js +22 -0
  19. data/javascripts/video.js +10 -0
  20. data/lib/pig-media-server/api.rb +96 -0
  21. data/lib/pig-media-server/aspect.rb +10 -5
  22. data/lib/pig-media-server/backup.rb +69 -0
  23. data/lib/pig-media-server/cli.rb +60 -25
  24. data/lib/pig-media-server/crawl.rb +41 -5
  25. data/lib/pig-media-server/kindle_send.rb +31 -24
  26. data/lib/pig-media-server/model/data.rb +106 -0
  27. data/lib/pig-media-server/model/migrate.rb +34 -0
  28. data/lib/pig-media-server/model/pig.rb +11 -2
  29. data/lib/pig-media-server/version.rb +1 -1
  30. data/lib/pig-media-server/views/_custom_links.haml +4 -0
  31. data/lib/pig-media-server/views/_ft_flv.haml +1 -0
  32. data/lib/pig-media-server/views/_ft_pdf.haml +0 -0
  33. data/lib/pig-media-server/views/_ft_video.haml +9 -4
  34. data/lib/pig-media-server/views/_link.haml +4 -1
  35. data/lib/pig-media-server/views/_new_flag.haml +1 -1
  36. data/lib/pig-media-server/views/app.scss +10 -1
  37. data/lib/pig-media-server/views/bundle.js +13 -0
  38. data/lib/pig-media-server/views/chromecast.coffee +54 -0
  39. data/lib/pig-media-server/views/config.coffee +13 -1
  40. data/lib/pig-media-server/views/config.haml +27 -4
  41. data/lib/pig-media-server/views/feed.builder +3 -2
  42. data/lib/pig-media-server/views/flv.coffee +33 -0
  43. data/lib/pig-media-server/views/index.haml +11 -5
  44. data/lib/pig-media-server/views/meta.haml +4 -4
  45. data/lib/pig-media-server/views/movie.coffee +65 -39
  46. data/lib/pig-media-server/views/react.haml +22 -0
  47. data/lib/pig-media-server/views/remote.haml +2 -2
  48. data/lib/pig-media-server/views/session.coffee +5 -0
  49. data/lib/pig-media-server/views/storage.coffee +5 -16
  50. data/lib/pig-media-server/views/sub.haml +5 -6
  51. data/lib/pig-media-server/views/subview.coffee +109 -19
  52. data/lib/pig-media-server/views/tv.coffee +97 -0
  53. data/lib/pig-media-server/views/tv.haml +33 -0
  54. data/lib/pig-media-server/views/unread.coffee +10 -0
  55. data/lib/pig-media-server/web.rb +102 -37
  56. data/package.json +23 -0
  57. data/pig-media-server.gemspec +5 -0
  58. metadata +123 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f32013836d4bf857c153d9c1637166e3cf261ca
4
- data.tar.gz: 0bffdde44cb7536875cae6239a5b2014ab0f874d
3
+ metadata.gz: 03172c241d9a720259504c431a3f24d3226dae28
4
+ data.tar.gz: cbd95152cf18824e2898e32562d61942d1ac525a
5
5
  SHA512:
6
- metadata.gz: 16333ea7be32edb98d89f82e1dbf7b37e9d3b407d810a09c66208ddf545c744ac7d4f020f66910c68601e56de6e29f5e381d63d8e0d4cb7b31c43a394b79f147
7
- data.tar.gz: d84211f9cb6b5ea9bd351b6e8d6752fa3b9833602928ac17d2468c13ebffcaf4e6f7e373d84b7179976c77fc7e16d3f68805ef83968792eedfff24f4b59e07e1
6
+ metadata.gz: 3e086f8d14b480451cd612f665b3971862601eaae32c43bf7771337befc492653b68fd1d132873e10a6408896519956145bb331f76c0c0ef8273605cb0e7cf9a
7
+ data.tar.gz: a95b3789b246eff2c3a0937def42c8983793b36696eec54229d52c2cc6b37d3687b38fccbf1d776e758b4e121fa4e851b94b338698d85d6defac8723b7a021dd
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ test/version_tmp
17
17
  tmp
18
18
  config.yaml
19
19
  vendor/bundle
20
+ node_modules
data/bin/pig-media-server CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
-
2
+ require 'bundler/setup'
3
+ Bundler.require
3
4
  require 'pig-media-server'
4
5
  require 'pig-media-server/cli'
6
+ PigMediaServer::CLI.start
7
+
data/gulpfile.js ADDED
@@ -0,0 +1,33 @@
1
+ var gulp = require('gulp');
2
+ var browserify = require('browserify');
3
+ var babelify = require('babelify');
4
+ var source = require('vinyl-source-stream');
5
+ var uglify = require('gulp-uglify');
6
+ var buffer = require('vinyl-buffer');
7
+ var cssDir = 'stylesheets'
8
+
9
+ gulp.task('browserify', function() {
10
+ browserify('./javascripts/application.js', { debug: true })
11
+ .transform(babelify)
12
+ .bundle()
13
+ .on("error", function (err) { console.log("Error : " + err.message); })
14
+ .pipe(source('bundle.js'))
15
+ .pipe(gulp.dest('./lib/pig-media-server/views/'))
16
+ });
17
+
18
+ gulp.task('build', function(){
19
+ browserify('./javascripts/application.js', { debug: true })
20
+ .transform(babelify)
21
+ .bundle()
22
+ .on("error", function (err) { console.log("Error : " + err.message); })
23
+ .pipe(source('bundle.js'))
24
+ .pipe(buffer())
25
+ .pipe(uglify())
26
+ .pipe(gulp.dest('./lib/pig-media-server/views/'))
27
+
28
+ });
29
+
30
+
31
+ gulp.task('watch', ['browserify'], function(){
32
+ gulp.watch('./javascripts/**/*.js', ['browserify']);
33
+ });
@@ -0,0 +1,117 @@
1
+ window.React = require('react');
2
+ window.ReactDOM = require('react-dom');
3
+ window.$ = window.jQuery = require('jquery');
4
+ window.moment = require('moment-timezone');
5
+
6
+ require('./chromecast.js');
7
+
8
+ require('./utils.js');
9
+ require('./controller.js');
10
+
11
+ require('./event_dispatcher.js');
12
+
13
+ require('./recent.js');
14
+ require('./video.js');
15
+ require('./custom_list.js');
16
+
17
+ require('./components/head.js');
18
+ require('./components/sort.js');
19
+ require('./components/list.js');
20
+ require('./components/query_list.js');
21
+ require('./components/new_flag.js');
22
+ require('./components/watch.js');
23
+ require('./components/player.js');
24
+
25
+ class Application extends React.Component {
26
+ constructor(props){
27
+ super(props);
28
+ this.controller = new Controller();
29
+ this.recent = new Recent(this);
30
+ this.video = new Video();
31
+ this.custom_list = new CustomList(this);
32
+
33
+ this.state = {
34
+ config: {},
35
+ session: {},
36
+ items: [],
37
+ recent: {},
38
+ video: null,
39
+
40
+ open: (link)=>{this.open(link)},
41
+ initialize: ()=>{this.initialize()},
42
+ update_state: ()=>{this.update_state()},
43
+
44
+ controller: this.controller,
45
+
46
+ models: {video: this.video, recent: this.recent, custom_list: this.custom_list}
47
+ }
48
+
49
+ this.state.models.video.addEventListener('videoUpdated', ()=>{ this.setState(this.state); });
50
+
51
+ window.addEventListener('popstate',(ev)=>{ this.initialize(); },false);
52
+ }
53
+
54
+ open(link){
55
+ history.pushState('', '', link);
56
+ this.initialize();
57
+ }
58
+
59
+ update_state(){ this.setState(this.state); }
60
+
61
+ load_from_api(url){
62
+ if(!!url){
63
+ $.get(url).done((data)=>{ this.state.items = data; this.update_state(); });
64
+ } else {
65
+ this.state.items = [];
66
+ this.update_state();
67
+ }
68
+ }
69
+
70
+ load_config(){ $.get("/api/r/config").done((data)=>{ this.state.config = data; this.update_state(); })}
71
+ load_session(){
72
+ $.get("/api/r/session").done((data)=>{
73
+ this.state.session = data;
74
+ this.update_state();
75
+ this.load_recent();
76
+ })
77
+ }
78
+
79
+ load_recent(){ this.recent.load() }
80
+
81
+ routing(){
82
+ var route = this.controller.route();
83
+ switch(route.page){
84
+ case "list":
85
+ this.load_from_api(this.controller.route().api_url);
86
+ this.state.active_page = 'list';
87
+ this.update_state();
88
+ break;
89
+ }
90
+ }
91
+
92
+ initialize(){
93
+ this.load_config();
94
+ this.load_session();
95
+ this.custom_list.load();
96
+ this.routing()
97
+ }
98
+
99
+ componentDidMount(){ this.initialize() }
100
+
101
+ render(){
102
+ return <div>
103
+ <Player state={this.state} />
104
+ <div id='all'>
105
+ <Head state={this.state} />
106
+ <SearchBox state={this.state}/>
107
+ <List state={this.state}/>
108
+ <QueryList state={this.state}/>
109
+ </div>
110
+ </div>
111
+ }
112
+ }
113
+
114
+ ReactDOM.render(<Application />, document.querySelector("#application"));
115
+
116
+
117
+
@@ -0,0 +1,57 @@
1
+ var currentMedia = null;
2
+ var currentVolume = 0.5;
3
+ var progressFlag = 1;
4
+ var mediaCurrentTime = 0;
5
+ var session = null;
6
+
7
+ var null_func = (obj)=>{''}
8
+
9
+ var sessionListener = (e)=>{
10
+ console.log('New session ID: ' + e.sessionId)
11
+ session = e
12
+ }
13
+
14
+ var onRequestSessionSuccess = (e)=>{
15
+ console.log("session success: " + e.sessionId)
16
+ session = e
17
+ if(session.media.length != 0){
18
+ onMediaDiscovered('onRequestSession', session.media[0])
19
+ }
20
+ session.addMediaListener(
21
+ onMediaDiscovered.bind(this, 'addMediaListener'))
22
+ }
23
+
24
+ var onMediaDiscovered = (how, media)=>{
25
+ console.log("new media session ID:" + media.mediaSessionId)
26
+ currentMedia = media
27
+ mediaCurrentTime = currentMedia.currentTime
28
+ }
29
+
30
+ var initializeCastApi = ()=>{
31
+ var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID)
32
+ var apiConfig = new chrome.cast.ApiConfig(sessionRequest, sessionListener, null_func)
33
+ chrome.cast.initialize(apiConfig, null_func, null_func)
34
+
35
+ console.log("launching app...")
36
+ chrome.cast.requestSession(onRequestSessionSuccess, null_func)
37
+ $('a.chromecast').show()
38
+ }
39
+
40
+ window.chrome_cast = (mediaURL, key)=>{
41
+ if(mediaURL.match(/pig.ssig33.com/)){
42
+ mediaURL = mediaURL.replace(/pig.ssig33.com\/volume/, 'ashare.ssig33.com');
43
+ mediaURL = mediaURL.replace(/https/, 'http');
44
+ mediaURL = mediaURL.replace(/^\/\//, 'http://');
45
+ console.log(mediaURL);
46
+ }
47
+ var mediaInfo = new chrome.cast.media.MediaInfo(mediaURL)
48
+ mediaInfo.contentType = 'video/mp4'
49
+ var request = new chrome.cast.media.LoadRequest(mediaInfo)
50
+ request.autoplay = true
51
+ request.currentTime = 0
52
+ session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), null_func)
53
+ }
54
+
55
+ window['__onGCastApiAvailable'] = (loaded, errorInfo)=>{
56
+ if(loaded){ initializeCastApi() }
57
+ }
@@ -0,0 +1,106 @@
1
+ class LoginAs extends React.Component {
2
+ render(){
3
+ return <span>Login as {this.props.user_id}</span>
4
+ }
5
+ }
6
+
7
+ class LoginLink extends React.Component {
8
+ render(){
9
+ return <a href='/sessions'>Login</a>
10
+ }
11
+ }
12
+
13
+ class Session extends React.Component {
14
+ render(){
15
+ return <div>
16
+ {this.props.state.session.user_id ?
17
+ <LoginAs user_id={this.props.state.session.user_id} /> :
18
+ <LoginLink />
19
+ }
20
+ </div>
21
+ }
22
+ }
23
+
24
+ class Head extends React.Component {
25
+ click(){
26
+ this.props.state.open('/');
27
+ }
28
+ render(){
29
+ return <div>
30
+ <Session state={this.props.state} />
31
+ <h2>
32
+ <a href='javascript:void(0)' onClick={()=> this.click()}>
33
+ {this.props.state.config.page_title}
34
+ </a>
35
+ </h2>
36
+ </div>
37
+ }
38
+ }
39
+
40
+ class CustomList extends React.Component{
41
+ click(){
42
+ this.props.state.open(`/custom?name=${encodeURIComponent(this.props.name)}`)
43
+ }
44
+ render(){
45
+ return <a href='javascript:void(0)' onClick={()=> this.click()}>{this.props.name}</a>
46
+ }
47
+ }
48
+
49
+ class Recommend extends React.Component{
50
+ click(){ this.props.state.open(`/recommend?name=${localStorage.user_id}`) }
51
+ render(){
52
+ return <span>
53
+ {!!localStorage.user_id ? <a href='javascript:void(0)' onClick={()=> this.click()}><b>Recommend</b></a> : null}
54
+ </span>
55
+ }
56
+ }
57
+
58
+ class SearchBox extends React.Component {
59
+ submit(event){
60
+ event.preventDefault();
61
+ var query = this.refs.input.value;
62
+ var url = `/?query=${encodeURIComponent(query)}`
63
+ history.pushState(url, '', url);
64
+ this.props.state.initialize();
65
+ }
66
+ click(e){ this.props.state.open(e.target.dataset.url); }
67
+
68
+ full_screen(){
69
+ var elem = document.querySelector("body");
70
+ if (elem.requestFullScreen) {
71
+ elem.requestFullScreen();
72
+ } else if (elem.mozRequestFullScreen) {
73
+ elem.mozRequestFullScreen();
74
+ } else if (elem.webkitRequestFullScreen) {
75
+ elem.webkitRequestFullScreen();
76
+ }
77
+ }
78
+
79
+ componentDidUpdate(){
80
+ var query = decodeURIComponent(this.props.state.controller.query());
81
+ if(query == 'undefined' || query == 'null' || !query){query = ''}
82
+ this.refs.input.value = query;
83
+ }
84
+
85
+
86
+
87
+ change(){ }
88
+
89
+ render(){
90
+ var query = decodeURIComponent(this.props.state.controller.query());
91
+ if(query == 'undefined' || query == 'null' || !query){query = ''}
92
+ var custom_list = $.map(this.props.state.models.custom_list.list, (v,k)=>{return <CustomList key={k} name={k} state={this.props.state}/>});
93
+ return <form onSubmit={(e)=> this.submit(e)}>
94
+ <input ref='input' defaultValue={query} onChange={()=>{this.change()}}/><button>Search</button>
95
+ <a href='javascript:void(0)' onClick={(e)=>this.click(e)} data-url='/latest'>Latest</a>
96
+ <a href='/config'>Config</a>
97
+ <a href='javascript:void(0)' onClick={()=> this.full_screen()}>Full Screen</a>
98
+ <Recommend state={this.props.state} />
99
+ <br />
100
+ {custom_list}
101
+ </form>
102
+ }
103
+ }
104
+
105
+ window.Head = Head;
106
+ window.SearchBox = SearchBox;
@@ -0,0 +1,104 @@
1
+ class CustomLinks extends React.Component{
2
+ render(){
3
+ return <span dangerouslySetInnerHTML={{__html: this.props.item.custom_links}}/>
4
+ }
5
+ }
6
+
7
+ class Item extends React.Component {
8
+ mtime(){
9
+ //moment(this.props.item.mtime)
10
+ return this.props.item.mtime;
11
+ }
12
+
13
+ render(){
14
+ var item = this.props.item;
15
+ var meta = `/meta/${this.props.item.key}`;
16
+ var sub = `/sub/${this.props.item.key}`;
17
+ return <span className='main_span'>
18
+ <NewFlag
19
+ item={this.props.item}
20
+ state={this.props.state}
21
+ />
22
+ <a href={item.url} className='main_link'>{item.name}</a>&nbsp;
23
+
24
+ <Watch
25
+ item={this.props.item}
26
+ state={this.props.state}
27
+ />
28
+ <ChromeCast
29
+ item={this.props.item}
30
+ state={this.props.state}
31
+ />
32
+ <span className='mtime'>{this.mtime()}</span>&nbsp;
33
+ <span className='size'>{size_pretty(item.size)}</span>&nbsp;
34
+ <a className='meta' href={meta}>Meta</a>
35
+ <a className='meta' href={sub}>Sub</a>
36
+ <CustomLinks item={this.props.item} />
37
+ </span>
38
+ }
39
+ }
40
+
41
+ class Pager extends React.Component {
42
+ constructor(props){
43
+ super(props);
44
+ this.page = 1;
45
+ var page = this.props.state.controller.params().page;
46
+ if(page){ this.page = parseInt(page)}
47
+ this.bind();
48
+ }
49
+
50
+ bind(){
51
+ $(window).on("scroll",()=>{
52
+ var scrollHeight = $(document).height();
53
+ var scrollPosition = $(window).height() + $(window).scrollTop();
54
+ if ((scrollHeight - scrollPosition) / scrollHeight === 0) {
55
+ if(this.props.state.controller.can_sort_and_paging()|| location.pathname == '/latest'){
56
+ this.click();
57
+ }
58
+ }
59
+ });
60
+ }
61
+ click(){
62
+ this.page ++;
63
+ if(location.pathname == '/latest'){
64
+ var url = this.props.state.controller.route().api_url += `?page=${this.page}`;
65
+ } else {
66
+ var url = this.props.state.controller.route().api_url += `&page=${this.page}`;
67
+ }
68
+ $.get(url).done((data)=>{
69
+ this.props.state.items = this.props.state.items.concat(data);
70
+ this.props.state.update_state();
71
+ if(location.pathname == '/latest'){
72
+ var new_url = `/latest?page=${this.page}`;
73
+ } else {
74
+ var new_url = `/?query=${this.props.state.controller.query()}&page=${this.page}`;
75
+ }
76
+ history.pushState('', '', new_url);
77
+ });
78
+ }
79
+
80
+ render(){ return <a href='javascript:void(0)' onClick={()=> this.click()}>Next</a> }
81
+ }
82
+
83
+
84
+ class List extends React.Component {
85
+ can_sort(){ return this.props.state.controller.can_sort_and_paging()}
86
+ render(){
87
+
88
+ var items = $.map(this.props.state.items, (item)=>{
89
+ return <Item
90
+ key={item.key}
91
+ state={this.props.state}
92
+ item={item}
93
+ />
94
+ });
95
+
96
+ return <div>
97
+ {this.can_sort() ? <Sort state={this.props.state} /> : null }
98
+ <p>{items}</p>
99
+ <p>{this.can_sort() || location.pathname == '/latest' ? <Pager state={this.props.state} /> : null }</p>
100
+ </div>
101
+ }
102
+ }
103
+
104
+ window.List = List;
@@ -0,0 +1,23 @@
1
+ class NewFlag extends React.Component{
2
+ is_new(){
3
+ if(!!this.props.state.recents){
4
+ var ext = window.ext(this.props.item.name);
5
+ if(ext == 'mp4' || ext == 'flv'){
6
+ var result = true;
7
+ $.each(this.props.state.recents, (k,v)=>{ if(k == `movie/${this.props.item.key}`){ result = false } });
8
+ return result
9
+ } else {
10
+ return false;
11
+ }
12
+ } else {
13
+ return false;
14
+ }
15
+ }
16
+
17
+ render(){
18
+ var is_new = this.is_new();
19
+ return <span>{is_new ? <span className='new_flag' style={{color:'lime', "fontWeight":'bold'}}>New</span> : null }</span>
20
+ }
21
+ }
22
+
23
+ window.NewFlag = NewFlag;
@@ -0,0 +1,171 @@
1
+ class Player extends React.Component {
2
+ constructor(props){
3
+ super(props);
4
+ this.current_url = '';
5
+ }
6
+ close(){ this.props.state.models.video.set(null); }
7
+ dom(){ return this.refs.video; }
8
+
9
+ video(){ return this.props.state.models.video.item; }
10
+
11
+ video_url(){
12
+ var url = null;
13
+ if(!!this.video()){ url = this.video().url; }
14
+ return url;
15
+ }
16
+
17
+ to_play(url){
18
+ if(!!url){
19
+ if(url != this.current_url){
20
+ this.current_url = url;
21
+ return true;
22
+ } else {
23
+ return false;
24
+ }
25
+ } else {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ next(){
31
+ var next = false;
32
+ var result;
33
+ var index = $.map(this.props.state.items, (e,i)=>{return e.key}).indexOf(this.props.state.models.video.item.key);
34
+ this.props.state.models.video.set(this.props.state.items[index-1]);
35
+ }
36
+
37
+ play(prev){
38
+ if(this.to_play(this.video_url())){
39
+ var node = this.dom();
40
+ node.addEventListener('canplay', (e)=>{
41
+ var target = e.target;
42
+ target.play();
43
+ this.props.state.models.recent.use(`movie/${this.video().key}`);
44
+
45
+ });
46
+ node.addEventListener('ended', (e)=>{ this.next(); });
47
+ node.load();
48
+ }
49
+ }
50
+
51
+ size_loop(){
52
+ if(!!this.video_url()){
53
+ var video_width = this.dom().videoWidth;
54
+ var video_height = this.dom().videoHeight;
55
+
56
+ var width = $(window).width();
57
+ var height = $(window).height();
58
+
59
+ var new_w, new_h;
60
+
61
+ if(parseFloat(video_height) / parseFloat(video_width) < parseFloat(height) / parseFloat(width)){
62
+ new_w = width;
63
+ new_h = parseInt((parseFloat(video_height) * (parseFloat(width) / parseFloat(video_width))));
64
+ } else {
65
+ new_w = parseInt((parseFloat(video_width) * (parseFloat(height) / parseFloat(video_height))));
66
+ new_h = height;
67
+ }
68
+ new_w = new_w - 10;
69
+ new_h = new_h - 10;
70
+
71
+ var spacer = (height - new_h) / 2;
72
+
73
+ $(this.dom()).css({width: new_w, height: new_h});
74
+ $(this.refs.spacer).css({height: spacer});
75
+ }
76
+ setTimeout(()=>{ this.size_loop()}, 200)
77
+ }
78
+
79
+ capture(){
80
+ var c = this.refs.canvas;
81
+ var v = this.dom();
82
+ var context = c.getContext('2d');
83
+ c.width = v.videoWidth;
84
+ c.height = v.videoHeight;
85
+ context.drawImage(v, 0, 0);
86
+ return c.toDataURL();
87
+ }
88
+
89
+ seek(count){ this.dom().currentTime += count; }
90
+ pause(){
91
+ this.dom().paused ? this.dom().play() : this.dom().pause();
92
+ }
93
+ gyazo(){
94
+ var url = this.capture();
95
+ $.post('/gyazo', {url: url, point: localStorage.gyazo}).done((data)=>{
96
+ window.open(data.url, "", "width=500,height=400");
97
+ });
98
+ }
99
+ tweet(){ $.post('/gyazo/tweet', {url: this.capture()}).success((data)=>{return true}); }
100
+ comment_tweet(){
101
+ var url = this.capture();
102
+ var comment = prompt('tweet');
103
+ if(!!comment){
104
+ $.post('/gyazo/tweet', {url: url, comment: comment}).success((data)=>{return true});
105
+ }
106
+ }
107
+
108
+
109
+ bind(){
110
+ $(window).keyup((e)=>{
111
+ if(!!$(this.dom()).attr('src')){
112
+ if(document.activeElement.tagName != 'INPUT'){
113
+ switch(e.keyCode){
114
+ case 74:
115
+ this.seek(14);
116
+ break;
117
+ case 75:
118
+ this.seek(-15);
119
+ break;
120
+ case 80:
121
+ this.pause();
122
+ break;
123
+ case 71:
124
+ this.gyazo();
125
+ break;
126
+ case 78:
127
+ this.next();
128
+ break;
129
+ case 67:
130
+ this.comment_tweet();
131
+ break;
132
+ case 84:
133
+ this.tweet();
134
+ break;
135
+ }
136
+ }
137
+ }
138
+ });
139
+ }
140
+
141
+ componentDidMount(){ this.size_loop(); this.bind(); }
142
+ componentDidUpdate(prev, prevState){ this.play(prev); }
143
+ video_name(){
144
+ if(!!this.video_url()){
145
+ return this.video().name;
146
+ } else {
147
+ return null;
148
+ }
149
+ }
150
+
151
+ class_name(){ if(!!this.video_url()){ return "" } else { return "none" } }
152
+
153
+ render(){
154
+ return <div className={this.class_name()} id='area'>
155
+ <div ref='spacer' />
156
+ <video
157
+ ref='video'
158
+ src={this.video_url()}
159
+ controls='controls'
160
+ onClick={()=> this.pause()}
161
+ />
162
+ <canvas className='none' ref='canvas' />
163
+ <div style={{height: '300px'}}/>
164
+ <a href='javascript:void(0)' onClick={()=> this.close()}>Close Video</a>
165
+ <br />
166
+ <span>{this.video_name()}</span>
167
+ </div>
168
+ }
169
+ }
170
+
171
+ window.Player = Player;