pig-media-server 0.3.2 → 2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/bin/pig-media-server +4 -1
- data/gulpfile.js +33 -0
- data/javascripts/application.js +117 -0
- data/javascripts/chromecast.js +57 -0
- data/javascripts/components/head.js +106 -0
- data/javascripts/components/list.js +104 -0
- data/javascripts/components/new_flag.js +23 -0
- data/javascripts/components/player.js +171 -0
- data/javascripts/components/query_list.js +68 -0
- data/javascripts/components/sort.js +64 -0
- data/javascripts/components/watch.js +48 -0
- data/javascripts/controller.js +62 -0
- data/javascripts/custom_list.js +14 -0
- data/javascripts/event_dispatcher.js +21 -0
- data/javascripts/recent.js +34 -0
- data/javascripts/utils.js +22 -0
- data/javascripts/video.js +10 -0
- data/lib/pig-media-server/api.rb +96 -0
- data/lib/pig-media-server/aspect.rb +10 -5
- data/lib/pig-media-server/backup.rb +69 -0
- data/lib/pig-media-server/cli.rb +60 -25
- data/lib/pig-media-server/crawl.rb +41 -5
- data/lib/pig-media-server/kindle_send.rb +31 -24
- data/lib/pig-media-server/model/data.rb +106 -0
- data/lib/pig-media-server/model/migrate.rb +34 -0
- data/lib/pig-media-server/model/pig.rb +11 -2
- data/lib/pig-media-server/version.rb +1 -1
- data/lib/pig-media-server/views/_custom_links.haml +4 -0
- data/lib/pig-media-server/views/_ft_flv.haml +1 -0
- data/lib/pig-media-server/views/_ft_pdf.haml +0 -0
- data/lib/pig-media-server/views/_ft_video.haml +9 -4
- data/lib/pig-media-server/views/_link.haml +4 -1
- data/lib/pig-media-server/views/_new_flag.haml +1 -1
- data/lib/pig-media-server/views/app.scss +10 -1
- data/lib/pig-media-server/views/bundle.js +13 -0
- data/lib/pig-media-server/views/chromecast.coffee +54 -0
- data/lib/pig-media-server/views/config.coffee +13 -1
- data/lib/pig-media-server/views/config.haml +27 -4
- data/lib/pig-media-server/views/feed.builder +3 -2
- data/lib/pig-media-server/views/flv.coffee +33 -0
- data/lib/pig-media-server/views/index.haml +11 -5
- data/lib/pig-media-server/views/meta.haml +4 -4
- data/lib/pig-media-server/views/movie.coffee +65 -39
- data/lib/pig-media-server/views/react.haml +22 -0
- data/lib/pig-media-server/views/remote.haml +2 -2
- data/lib/pig-media-server/views/session.coffee +5 -0
- data/lib/pig-media-server/views/storage.coffee +5 -16
- data/lib/pig-media-server/views/sub.haml +5 -6
- data/lib/pig-media-server/views/subview.coffee +109 -19
- data/lib/pig-media-server/views/tv.coffee +97 -0
- data/lib/pig-media-server/views/tv.haml +33 -0
- data/lib/pig-media-server/views/unread.coffee +10 -0
- data/lib/pig-media-server/web.rb +102 -37
- data/package.json +23 -0
- data/pig-media-server.gemspec +5 -0
- metadata +123 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03172c241d9a720259504c431a3f24d3226dae28
|
4
|
+
data.tar.gz: cbd95152cf18824e2898e32562d61942d1ac525a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e086f8d14b480451cd612f665b3971862601eaae32c43bf7771337befc492653b68fd1d132873e10a6408896519956145bb331f76c0c0ef8273605cb0e7cf9a
|
7
|
+
data.tar.gz: a95b3789b246eff2c3a0937def42c8983793b36696eec54229d52c2cc6b37d3687b38fccbf1d776e758b4e121fa4e851b94b338698d85d6defac8723b7a021dd
|
data/.gitignore
CHANGED
data/bin/pig-media-server
CHANGED
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>
|
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>
|
33
|
+
<span className='size'>{size_pretty(item.size)}</span>
|
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;
|