Skip to content

Commit

Permalink
Fix events for when users scrubs through time
Browse files Browse the repository at this point in the history
  • Loading branch information
davidvanleeuwen committed May 14, 2024
1 parent a6268d6 commit bb7b4f1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 71 deletions.
4 changes: 2 additions & 2 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 38 additions & 23 deletions client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import Data from './data';
import Logger from './logger';

enum NativeEvents {
DURATIONCHANGE = "durationchange",
LOADEDMETADATA = "loadedmetadata",
TIMEUPDATE = "timeupdate",
LOADEDDATA = "loadeddata",
CANPLAY = "canplay",
CANPLAYTHROUGH = "canplaythrough",
SEEKED = "seeked",
RATECHANGE = "ratechange",
VOLUMECHANGE = "volumechange",
DURATIONCHANGE = 'durationchange',
LOADEDMETADATA = 'loadedmetadata',
TIMEUPDATE = 'timeupdate',
LOADEDDATA = 'loadeddata',
CANPLAY = 'canplay',
CANPLAYTHROUGH = 'canplaythrough',
SEEKING = 'seeking',
SEEKED = 'seeked',
RATECHANGE = 'ratechange',
VOLUMECHANGE = 'volumechange',
PLAYING = 'playing',
ENDED = 'ended',
PLAY = 'play',
Expand Down Expand Up @@ -39,9 +40,8 @@ export class Metrics {
#video!: HTMLVideoElement;
#session!: Channel;

#lastLastLastCurrentTime = 0;
#lastLastCurrentTime = 0;
#lastCurrentTime = 0;
#lastTime?: number;
#lastEventType?: null | 'play' | 'pause' = null;
bufferInterval?: ReturnType<typeof setInterval>;
bufferTimeInterval = 50;
bufferOffset = (this.bufferTimeInterval - 40) / 1000;
Expand Down Expand Up @@ -232,19 +232,27 @@ export class Metrics {

switch (event.type) {
case NativeEvents.PLAYING:
if (this.#lastEventType === 'play') {
break;
}

this.#session?.push(
'event',
{
...params,
name: 'play',
from: this.#currentTime(),
// remove time shifting (play > playing)
from: this.#video?.currentTime < 1 ? 0 : this.#currentTime()
},
this.timeout
);

this.#lastEventType = 'play';

break;
case NativeEvents.PAUSE:
if (this.#video?.readyState === 4) {
if(this.#lastEventType === 'pause') break;
this.#session?.push(
'event',
{
Expand All @@ -255,28 +263,35 @@ export class Metrics {
);
}

this.#lastEventType = 'pause';

break;
case NativeEvents.SEEKED:
// ignore time shift
if (Math.abs(this.#lastLastLastCurrentTime - this.#lastLastCurrentTime) > 0.5) {

case NativeEvents.TIMEUPDATE:
if (this.#video?.ended) {
this.#lastTime = undefined;
break;
}

if (this.#lastTime && !this.#video.paused && Math.abs(this.#video?.currentTime - this.#lastTime) > 0.5) {
if (this.#lastEventType === 'pause') break;
this.#session?.push(
'event',
{
...params,
name: 'pause',
to: this.#lastLastLastCurrentTime,
to: this.#lastTime,
},
this.timeout
);

this.#lastEventType = 'pause';
}
break;
case NativeEvents.TIMEUPDATE:
this.#lastLastLastCurrentTime = this.#lastLastCurrentTime;
this.#lastLastCurrentTime = this.#lastCurrentTime;
this.#lastCurrentTime = this.#video?.currentTime;
break;

this.#lastTime = this.#video?.currentTime;
break;
}

}

#currentTime() {
Expand Down
98 changes: 52 additions & 46 deletions server/lib/mave_metrics/stats.ex
Original file line number Diff line number Diff line change
Expand Up @@ -125,55 +125,61 @@ defmodule MaveMetrics.Stats do
def create_durations(events) do
events
|> Enum.filter(&(&1.type == :pause))
|> Enum.map(fn pause_event ->
|> Enum.reduce([], fn pause_event, acc ->
play_event = find_play_event_for(pause_event, events)

watched_seconds =
Int4Range.new(
round(play_event.video_time),
(Float.floor(pause_event.video_time) |> trunc()) + 1
)

overlapping_durations =
Duration
|> where(
[d],
d.session_id == ^pause_event.session_id and d.video_id == ^pause_event.video_id
)
|> where([d], fragment("? && ?", d.watched_seconds, type(^watched_seconds, Int4Range)))
|> select([d], %{
overlap:
fragment(
"upper(? * ?) - lower(? * ?)",
d.watched_seconds,
type(^watched_seconds, Int4Range),
d.watched_seconds,
type(^watched_seconds, Int4Range)
)
})
|> Repo.all()

total_duration = round(pause_event.video_time) - round(play_event.video_time) + 1
total_overlap = Enum.sum(for %{overlap: o} <- overlapping_durations, do: o)
uniqueness = (total_duration - total_overlap) / total_duration
uniqueness = if uniqueness < 0, do: 0.0, else: uniqueness

session = Session |> Repo.get!(pause_event.session_id)

%{
timestamp: pause_event.timestamp,
duration: Float.round(pause_event.video_time - play_event.video_time, 2),
session_id: pause_event.session_id,
video_id: pause_event.video_id,
uniqueness: uniqueness,
watched_seconds: watched_seconds,
browser: session.browser,
platform: session.platform,
device: session.device,
uri_host: session.uri_host,
uri_path: session.uri_path
}
if play_event && pause_event.video_time >= play_event.video_time do
lower_bound = round(play_event.video_time)
upper_bound = (Float.floor(pause_event.video_time) |> trunc()) + 1

watched_seconds = Int4Range.new(lower_bound, upper_bound)

overlapping_durations =
Duration
|> where(
[d],
d.session_id == ^pause_event.session_id and d.video_id == ^pause_event.video_id
)
|> where([d], fragment("? && ?", d.watched_seconds, type(^watched_seconds, Int4Range)))
|> select([d], %{
overlap:
fragment(
"upper(? * ?) - lower(? * ?)",
d.watched_seconds,
type(^watched_seconds, Int4Range),
d.watched_seconds,
type(^watched_seconds, Int4Range)
)
})
|> Repo.all()

total_duration = round(pause_event.video_time) - round(play_event.video_time) + 1
total_overlap = Enum.sum(for %{overlap: o} <- overlapping_durations, do: o)
uniqueness = (total_duration - total_overlap) / total_duration
uniqueness = if uniqueness < 0, do: 0.0, else: uniqueness

session = Session |> Repo.get!(pause_event.session_id)

duration_map = %{
timestamp: pause_event.timestamp,
duration: Float.round(pause_event.video_time - play_event.video_time, 2),
session_id: pause_event.session_id,
video_id: pause_event.video_id,
uniqueness: uniqueness,
watched_seconds: watched_seconds,
browser: session.browser,
platform: session.platform,
device: session.device,
uri_host: session.uri_host,
uri_path: session.uri_path
}

[duration_map | acc]
else
acc
end
end)
|> Enum.reverse()
end

defp find_play_event_for(pause_event, events) do
Expand Down

0 comments on commit bb7b4f1

Please sign in to comment.