-
Notifications
You must be signed in to change notification settings - Fork 1
/
playday.js
167 lines (150 loc) · 5.53 KB
/
playday.js
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// here we declare our Playday class in what has become the defacto way
// if this were an NPM module, we would be using require and module.exports
(function(){
// jquery makes this simpler (react, angular, etc. would be overkill)
var $ = window.jQuery;
// our constructor, we don't do any real work here but we
// init the settings and DOM node references we'll need later
var Playday = function(options) {
options = options || {};
nodes = options.nodes || {};
this.baseUrl = options.baseUrl;
this.username = options.username;
this.password = options.password;
this.videos = [],
// having node references decouples us from the markup
this.nodes = {
screen: $(nodes.screen),
playlist: $(nodes.playlist),
title: $(nodes.title),
desc: $(nodes.desc),
error: $(nodes.error),
prev: $(nodes.prev),
next: $(nodes.next),
what: $(nodes.what)
};
}
Playday.prototype.load = function() {
// wire up prev/next/what buttons
// note how we use bind() to ensure instance scope
var nodes = this.nodes;
nodes.prev.click(this.prev.bind(this));
nodes.next.click(this.next.bind(this));
nodes.what.click(this.toggleWhat.bind(this));
// fetch the videos from mediacore (this is the only request we make)
// when the data comes back, hang onto it, build a playlist and autoplay
this.getVideos().success(function(data) {
this.videos = data.items;
this.renderPlaylist();
this.play(0);
}.bind(this));
}
// get the videos, we use joins to get everything we need in one call
// note: we craft the basic-auth header manually because jQuery's
// username/password fields don't appear to work with CORS
Playday.prototype.getVideos = function() {
return $.get({
url: this.baseUrl + 'media',
data: {type: 'video', joins: 'thumbs,embedcode'},
beforeSend: function(xhr) {
xhr.setRequestHeader(
'Authorization',
'Basic ' + btoa(this.username + ':' + this.password)
);
}.bind(this),
}).fail(function(xhr){
this.nodes.error.text('Failed to get videos: ' + xhr.statusText).show();
}.bind(this));
}
// populate the playlist node with videos
// each video gets a thumbnail, a title and plays when clicked
Playday.prototype.renderPlaylist = function() {
this.nodes.playlist.empty();
for (i in this.videos) {
// these deep references are fragile, so we try/catch them
// skipping over any bad entries and logging the errors
try {
var title = this.videos[i].title;
var src = this.videos[i].joins.thumbs.sizes.l;
} catch (e) {
console.log(e);
continue;
}
// note how we pass the video index through the click event so we can
// use bind and have instance scope (otherwise 'this' would be our thumb)
var thumb = $('<div></div>')
.click(i, function(e) { this.play(parseInt(e.data, 10)); }.bind(this))
.addClass('thumb')
.append($('<img>').attr('src', src))
.append($('<div></div>').text(title))
.appendTo(this.nodes.playlist);
}
}
// play the specified video using playerjs
Playday.prototype.play = function(index) {
this.current = index;
var video = this.videos[index]
var nodes = this.nodes;
// playerjs takes an iframe, start by applying the embedcode to our 'screen'
// then hand it off to playerjs (this is the only place we touch playerjs)
nodes.screen.html(video.joins.embedcode.html);
var player = new playerjs.Player(nodes.screen.find('iframe')[0]);
player.on('ready', function() { player.play(); });
player.on('ended', function() { this.next(); }.bind(this));
// update the other parts of our interface (title, desc, playlist)
nodes.title.text(video.title);
nodes.desc.text(video.description_plain);
nodes.playlist.find('.thumb.selected').removeClass('selected');
nodes.playlist.find('.thumb').eq(index).addClass('selected');
}
Playday.prototype.prev = function() {
this.play(
this.current > 0
? this.current - 1
: this.videos.length - 1
);
}
Playday.prototype.next = function() {
this.play(
this.current < this.videos.length - 1
? this.current + 1
: 0
);
}
// ...felt like doing something silly
// this toggles on/off a bizarre filtering effect
Playday.prototype.toggleWhat = function() {
if (!this.interval) {
this.cycle = 0;
this.interval = window.setInterval(this.what.bind(this), 250);
} else {
window.clearInterval(this.interval);
this.interval = null;
this.nodes.screen.css({
'filter': 'none',
'-webkit-filter': 'none'
});
}
}
// apply css filters to produce a strange inverted video
Playday.prototype.what = function() {
var odd = this.cycle++ % 2;
var filters = [
'invert(' + (odd ? '90' : '100') + '%)',
'contrast(' + this.random(100, 200) + '%)',
'saturate(' + this.random(50, 150) + '%)',
'brightness(' + this.random(100, 150) + '%)',
'hue-rotate(' + this.random(0, 360) + 'deg)'
];
this.nodes.screen.css({
'filter': filters.join(' '),
'-webkit-filter': filters.join(' ')
});
}
// produce a random integer between min/max inclusive
Playday.prototype.random = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// export our 'module'
window.Playday = Playday;
})();