Skip to content

Commit c5515b8

Browse files
author
Dave Newman
committed
Sync chat with recorded videos
1 parent fc15262 commit c5515b8

File tree

10 files changed

+77
-27
lines changed

10 files changed

+77
-27
lines changed

app/assets/javascripts/components/Chat.es6.jsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
let messageId = 1
22

3+
function pollUntil(condition, action, interval=100) {
4+
if (!condition()) {
5+
return setTimeout(() => pollUntil(condition, action, interval), interval)
6+
}
7+
8+
action()
9+
}
10+
11+
312
class Chat extends React.Component {
413
constructor(props) {
514
super(props)
@@ -26,7 +35,13 @@ class Chat extends React.Component {
2635
}
2736

2837
renderComments() {
29-
return this.state.comments.map(c =>
38+
let visibleComments = this.state.comments
39+
const start = this.props.stream.recording_started_at
40+
if (start) {
41+
const current = start + this.state.timeOffset
42+
visibleComments = this.state.comments.filter(c => c.created_at < current)
43+
}
44+
return visibleComments.map(c =>
3045
<ChatComment
3146
key={c.id}
3247
id={c.id}
@@ -37,7 +52,11 @@ class Chat extends React.Component {
3752
}
3853

3954
renderChatInput() {
40-
if (this.props.active && this.pusher) {
55+
const allowChat = this.props.signedIn &&
56+
this.state.channel &&
57+
this.props.stream.archived_at === null
58+
59+
if (allowChat) {
4160
return (
4261
<form onSubmit={this.handleSubmit.bind(this)}>
4362
<input type="text" ref="body" defaultValue="" placeholder="Ask question" className="col-9 focus-no-border font-sm resize-chat-on-change m0" style={{"border": "none", "outline": "none"}} />
@@ -71,7 +90,7 @@ class Chat extends React.Component {
7190
method: 'POST',
7291
dataType: 'json',
7392
data: {
74-
socket_id: this.pusher.connection.socket_id,
93+
socket_id: this.state.pusher.connection.socket_id,
7594
comment: {
7695
article_id: this.props.stream.id,
7796
body: this.refs.body.value,
@@ -123,15 +142,21 @@ class Chat extends React.Component {
123142
}
124143

125144
componentWillMount() {
126-
this.pusher = new Pusher(this.props.pusherKey)
127-
this.channel = this.pusher.subscribe(this.props.chatChannel)
145+
pollUntil(
146+
() => typeof Pusher !== 'undefined',
147+
() => {
148+
const pusher = new Pusher(this.props.pusherKey)
149+
const channel = pusher.subscribe(this.props.chatChannel)
150+
channel.bind('new-comment', comment => {
151+
this.setState({comments: [...this.state.comments, comment]})
152+
})
153+
154+
this.setState({pusher, channel})
155+
}
156+
)
128157
}
129158

130159
componentDidMount() {
131-
this.channel.bind('new-comment', comment => {
132-
this.setState({comments: [...this.state.comments, comment]})
133-
})
134-
135160
const self = this
136161
$(this.refs.scrollable).bind('mousewheel DOMMouseScroll', function(e) {
137162
if (this.scrollTop < 100) {
@@ -146,6 +171,7 @@ class Chat extends React.Component {
146171
this.scrollToBottom()
147172
this.fetchOlderChatMessages()
148173
$(window).on('video-resize', this.constrainChatToStream)
174+
$(window).on('video-time', (e, data) => this.setState({ timeOffset: data.position }))
149175
}
150176

151177
componentWillUnmount() {
@@ -184,8 +210,7 @@ class Chat extends React.Component {
184210
Chat.propTypes = {
185211
chatChannel: React.PropTypes.string.isRequired,
186212
comments: React.PropTypes.array.isRequired,
187-
isLive: React.PropTypes.bool,
188213
pusherKey: React.PropTypes.string.isRequired,
189-
active: React.PropTypes.bool,
214+
signedIn: React.PropTypes.bool,
190215
stream: React.PropTypes.object.isRequired,
191216
}

app/assets/javascripts/components/Video.es6.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Video extends React.Component {
2727
}).on('play', () => this.setState({online: true}))
2828
.on('bufferFull', () => this.setState({online: true}))
2929
.on('resize', data => $(window).trigger('video-resize', data))
30+
.on('time', data => $(window).trigger('video-time', data))
3031
.onError(this.onError.bind(this))
3132

3233
// debug
@@ -80,9 +81,9 @@ class Video extends React.Component {
8081
}
8182

8283
onAll(e, data) {
83-
if (e !== 'time' && e !== 'meta') {
84+
// if (e !== 'time' && e !== 'meta') {
8485
console.log(e, data)
85-
}
86+
// }
8687
}
8788
}
8889

app/controllers/quickstream_controller.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ class QuickstreamController < ApplicationController
22
skip_before_action :verify_authenticity_token
33

44
def webhook
5-
@user = User.find_by!(stream_key: params[:token])
5+
case params[:type].to_sym
6+
when :auth
7+
@user = User.find_by!(stream_key: params[:token])
8+
when :youtube_live
9+
puts params[:broadcast]
10+
broadcast_id = params[:broadcast]['id']
11+
@stream = Stream.joins(:user).find_by!('users.username' => params[:streamer], :recording_id => broadcast_id)
12+
@stream.update!(recording_started_at: Time.parse(params[:broadcast]['snippet']['actual_start_time']))
13+
end
614
render nothing: true, status: :ok
715
end
816
end

app/controllers/streams_controller.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,13 @@ def save_and_redirect
9898
if @stream.save
9999
case
100100
when @stream.archived?
101+
@stream.touch(:archived_at)
101102
end_youtube_stream
102103
flash[:notice] = "You are offline and your broadcast was archived"
103104
redirect_to new_stream_path
104105
when @stream.published?
105106
Rails.logger.info("pushing to youtube")
106-
stream_to_youtube if @stream.save_recording
107+
stream_to_youtube
107108
redirect_to profile_stream_path(current_user.username)
108109
else
109110
redirect_to new_stream_path

app/models/comment.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ class Comment < ActiveRecord::Base
33
paginates_per 10
44
html_schema_type :Comment
55

6+
VIDEO_LAG = 25.seconds # TODO: measure the real lag value
7+
68
after_create :auto_like_article_for_author
79

810
belongs_to :user, touch: true, required: true
@@ -20,4 +22,8 @@ def dom_id
2022
def auto_like_article_for_author
2123
article.likes.create(user: user) unless user.likes?(article)
2224
end
25+
26+
def video_timestamp
27+
(created_at - VIDEO_LAG).to_i
28+
end
2329
end

app/models/stream.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def preview_image_url
5151
end
5252

5353
def source
54-
if recording_id
54+
if archived?
5555
"//www.youtube.com/watch?v=#{recording_id}"
5656
else
5757
user.stream_source
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
json.extract! comment, :id, :created_at
1+
json.extract! comment, :id
2+
json.created_at comment.video_timestamp
23
json.authorUrl user_path(comment.user)
34
json.authorUsername comment.user.username
45
json.markup sanitize(CoderwallFlavoredMarkdown.render_to_html(comment.body))

app/views/streams/show.json.jbuilder

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ if current_user
22
json.authorUrl user_path(current_user)
33
json.authorUsername current_user.username
44
end
5-
json.pusherKey ENV['PUSHER_KEY']
65
json.chatChannel @stream.dom_id
6+
json.pusherKey ENV['PUSHER_KEY']
7+
json.signedIn !!current_user
78

89
json.stream do
9-
json.extract! @stream, :id, :active
10+
json.extract! @stream, :id, :archived_at
11+
json.recording_started_at @stream.recording_started_at.try(:to_i)
1012
end
1113

1214
json.comments @comments, partial: 'comments/comment', as: :comment
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddRecordingStartedAtToProtips < ActiveRecord::Migration
2+
def change
3+
add_column :protips, :recording_started_at, :datetime
4+
end
5+
end

db/schema.rb

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#
1212
# It's strongly recommended that you check this file into your version control system.
1313

14-
ActiveRecord::Schema.define(version: 20160607202132) do
14+
ActiveRecord::Schema.define(version: 20160608034824) do
1515

1616
# These are extensions that must be enabled in order to support this database
1717
enable_extension "plpgsql"
@@ -97,17 +97,18 @@
9797
t.integer "user_id"
9898
t.float "score"
9999
t.datetime "featured_at"
100-
t.datetime "created_at", null: false
101-
t.datetime "updated_at", null: false
102-
t.string "tags", default: [], array: true
103-
t.integer "likes_count", default: 0
104-
t.integer "views_count", default: 0
105-
t.boolean "flagged", default: false
106-
t.text "type", null: false
100+
t.datetime "created_at", null: false
101+
t.datetime "updated_at", null: false
102+
t.string "tags", default: [], array: true
103+
t.integer "likes_count", default: 0
104+
t.integer "views_count", default: 0
105+
t.boolean "flagged", default: false
106+
t.text "type", null: false
107107
t.datetime "published_at"
108108
t.datetime "archived_at"
109109
t.boolean "save_recording"
110110
t.text "recording_id"
111+
t.datetime "recording_started_at"
111112
end
112113

113114
add_index "protips", ["created_at"], name: "index_protips_on_created_at", using: :btree

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy