diff options
| author | Aurélien Warnon <awa@odoo.com> | 2020-06-30 12:29:03 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-08-04 14:28:29 +0000 |
| commit | fab82c73a5aeb31a3be970dfe31ac754597dbb78 (patch) | |
| tree | 59e9e1e7b074a011f08134230603950f9e63899d /addons/website_event_track_live/static/src | |
| parent | e73ec2ddb90b105bfad72a018726eaf3ac38e21c (diff) | |
[ADD] website_event_track_live: configure Youtube videos / streams on event.tracks
RATIONALE
Events are sometimes held online, gathering a community. In this merge we
improve Event application to better support full-online events with improved
tracks, wishlists, chat rooms, ...
PURPOSE
Allow to include a youtube video / live stream on event tracks and update the
interface to show "online" capabilities.
SPECIFICATIONS
This commit improves the existing event.tracks to include the possibility to
configure a Youtube live stream or video.
The frontend view of the track was adapted accordingly to show the stream /
video instead of the track description when available.
At the end of the video, the track view will automatically suggest a next track
to the attendee in order to keep him looping through interesting tracks.
Those suggestions are based on an algorithm that tries to select the track that
would be the most interesting to this attendee based on his wishlist, similar
tags with current track, same room, ...
In addition, we automatically fallback to a Youtube thumbnail for tracks
website image when available.
We support two youtube modes
* streaming: start and end of video is detected based on youtube API;
* replay: boolean flag on track, telling the video is a static one, allowing
to know by advance the end of video, and to pre-compute thumbnail and give
early access if necessary;
KNOWN LIMITATIONS
Tracks do not hold any protection for payment-based tickets. Everything that
is published is available using standard ACLs. Content protection based on
tickets is currently not supported.
LINKS
Task ID-2252655 (Main Online Event task)
Task ID-2283735 (Talks -> Session upgrade)
Task ID-2283729 (Live/Youtube Tracks)
Co-Authored-By: Aurélien Warnon <awa@odoo.com>
Co-Authored-By: David Beguin <dbe@odoo.com>
Co-Authored-By: Thibault Delavallée <tde@odoo.com>
Diffstat (limited to 'addons/website_event_track_live/static/src')
4 files changed, 277 insertions, 0 deletions
diff --git a/addons/website_event_track_live/static/src/js/website_event_track_live.js b/addons/website_event_track_live/static/src/js/website_event_track_live.js new file mode 100644 index 00000000000..a330308de63 --- /dev/null +++ b/addons/website_event_track_live/static/src/js/website_event_track_live.js @@ -0,0 +1,121 @@ +var onYouTubeIframeAPIReady; + +odoo.define('website_event_track_live.website_event_youtube_embed', function (require) { +'use strict'; + +var publicWidget = require('web.public.widget'); +var TrackSuggestionWidget = require('website_event_track_live.website_event_track_suggestion'); + +var YOUTUBE_VIDEO_ENDED = 0; +var YOUTUBE_VIDEO_PLAYING = 1; +var YOUTUBE_VIDEO_PAUSED = 2; + +publicWidget.registry.websiteEventTrackLive = publicWidget.Widget.extend({ + selector: '.o_wevent_event_track_live', + custom_events: _.extend({}, publicWidget.Widget.prototype.custom_events, { + 'video-ended': '_onVideoEnded' + }), + + start: function () { + var self = this; + return this._super(...arguments).then(function () { + self._setupYoutubePlayer(); + self.isFullScreen = !!document.fullscreenElement; + }); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + _onPlayerReady: function () { + $(window).on('resize', this._onResize.bind(this)); + this.$('.o_wevent_event_track_live_loading').remove(); + }, + + _onPlayerStateChange: function (event) { + if (event.data === YOUTUBE_VIDEO_ENDED) { + this.trigger('video-ended'); + } else if (event.data === YOUTUBE_VIDEO_PLAYING) { + this.trigger('video-playing'); + } else if (event.data === YOUTUBE_VIDEO_PAUSED) { + this.trigger('video-paused'); + } + }, + + _onVideoEnded: function () { + var self = this; + this._rpc({ + route: '/event_track/get_track_suggestion', + params: { + track_id: this.$el.data('trackId'), + } + }).then(function (suggestion) { + self.nextSuggestion = suggestion; + self._showSuggestion(); + }); + }, + + _onReplay: function () { + this.youtubePlayer.seekTo(0); + this.youtubePlayer.playVideo(); + if (this.trackSuggestion) { + delete this.trackSuggestion; + } + }, + + /** + * The 'fullscreenchange' event is probably a better fit but it is unfortunately + * not triggered when Youtube enters fullscreen mode. + * However, the global window 'resize' is. + */ + _onResize: function () { + this.isFullScreen = !!document.fullscreenElement; + this._showSuggestion(); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + _setupYoutubePlayer: function () { + var self = this; + + var youtubeId = self.$el.data('youtubeVideoId'); + var $youtubeElement = $('<script/>', {src: 'https://www.youtube.com/iframe_api'}); + $(document.head).append($youtubeElement); + + onYouTubeIframeAPIReady = function () { + self.youtubePlayer = new YT.Player('o_wevent_youtube_iframe_container', { + height: '100%', + width: '100%', + videoId: youtubeId, + playerVars: { + autoplay: 1, + enablejsapi: 1, + rel: 0, + origin: window.location.origin, + widget_referrer: window.location.origin, + }, + events: { + 'onReady': self._onPlayerReady.bind(self), + 'onStateChange': self._onPlayerStateChange.bind(self) + } + }); + }; + }, + + /** + * Automatically launches the next suggested track when this one ends + * and the user is not in fullscreen mode. + */ + _showSuggestion: function () { + if (this.nextSuggestion && !this.isFullScreen && !this.trackSuggestion) { + this.trackSuggestion = new TrackSuggestionWidget(this, this.nextSuggestion); + this.trackSuggestion.appendTo(this.$el); + this.trackSuggestion.on('replay', null, this._onReplay.bind(this)); + } + } +}); + +}); diff --git a/addons/website_event_track_live/static/src/js/website_event_track_suggestion.js b/addons/website_event_track_live/static/src/js/website_event_track_suggestion.js new file mode 100644 index 00000000000..e6583c22509 --- /dev/null +++ b/addons/website_event_track_live/static/src/js/website_event_track_suggestion.js @@ -0,0 +1,81 @@ +odoo.define('website_event_track_live.website_event_track_suggestion', function (require) { +'use strict'; + +var Widget = require('web.Widget'); + +var WebsiteEventTrackSuggestion = Widget.extend({ + template: 'website_event_track_live.website_event_track_suggestion', + xmlDependencies: ['/website_event_track_live/static/src/xml/website_event_track_live_templates.xml'], + events: { + 'click .owevent_track_suggestion_next': '_onNextTrackClick', + 'click .owevent_track_suggestion_close': '_onCloseClick', + 'click .owevent_track_suggestion_replay': '_onReplayClick' + }, + + init: function (parent, options) { + this._super(...arguments); + + this.currentTrack = { + 'name': options.current_track.name, + 'imageSrc': options.current_track.website_image_url, + }; + this.suggestion = { + 'name': options.suggestion.name, + 'speakerName': options.suggestion.speaker_name, + 'trackUrl': options.suggestion.website_url, + }; + }, + + start: function () { + var self = this; + this._super(...arguments).then(function () { + self.timerInterval = setInterval(self._updateTimer.bind(self), 1000); + }); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * If the user clicks on replay, remove this suggestion window and send an + * event to the parent so that it can rewind the video to the beginning. + */ + _onReplayClick: function () { + this.trigger_up('replay'); + clearInterval(this.timerInterval); + this.destroy(); + }, + + _onCloseClick: function () { + clearInterval(this.timerInterval); + this.$('.owevent_track_suggestion_next').addClass('invisible'); + }, + + _onNextTrackClick: function (ev) { + if ($(ev.target).hasClass('owevent_track_suggestion_close')) { + return; + } + + window.location = this.suggestion.trackUrl; + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + _updateTimer: function () { + var secondsLeft = parseInt(this.$('.owevent_track_suggestion_timer_text').text()); + + if (secondsLeft > 1) { + secondsLeft -= 1; + this.$('.owevent_track_suggestion_timer_text').text(secondsLeft); + } else { + window.location = this.suggestion.trackUrl; + } + } +}); + +return WebsiteEventTrackSuggestion; + +}); diff --git a/addons/website_event_track_live/static/src/scss/website_event_track_live.scss b/addons/website_event_track_live/static/src/scss/website_event_track_live.scss new file mode 100644 index 00000000000..28571e01ffa --- /dev/null +++ b/addons/website_event_track_live/static/src/scss/website_event_track_live.scss @@ -0,0 +1,42 @@ +.o_wesession_track_aside_tab_chat { + height: 70vh; +} + +#o_wevent_youtube_iframe_container, .o_wevent_event_track_live_loading { + height: 85vh; +} + +.o_wevent_event_track_live_loading { + background-color: #888888; + + i { + bottom: 1px; + } +} + +.owevent_track_suggestion { + background-color: #888888; + background-repeat: no-repeat; + background-size: 100% 100%; + height: 85vh; + top: 0px; + left: 0px; + + .owevent_track_suggestion_content { + background-color: rgba(0,0,0,.5); + + .owevent_track_suggestion_next { + background-color: rgba(0,0,0,.5); + transition: background-color .3s linear; + &:hover { + cursor: pointer; + background-color: rgba(0,0,0,.9); + } + + .owevent_track_suggestion_close { + top: .5rem; + right: .5rem; + } + } + } +} diff --git a/addons/website_event_track_live/static/src/xml/website_event_track_live_templates.xml b/addons/website_event_track_live/static/src/xml/website_event_track_live_templates.xml new file mode 100644 index 00000000000..1784afae39c --- /dev/null +++ b/addons/website_event_track_live/static/src/xml/website_event_track_live_templates.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<templates xml:space="preserve"> + +<div t-name="website_event_track_live.website_event_track_suggestion" + class="owevent_track_suggestion position-absolute w-100" + t-attf-style="background-image: url('#{widget.currentTrack.imageSrc}');"> + <div class="h-100 w-100 p-4 d-flex flex-column align-items-center owevent_track_suggestion_content"> + <div class="flex-grow-1 pt-5 d-flex flex-column align-items-center justify-content-center"> + <div class="text-white">You just watched:</div> + <div class="h1 text-white" t-esc="widget.currentTrack.name"/> + <div> + <a href="#" class="owevent_track_suggestion_replay font-weight-bold"> + <span>Replay Video</span> + </a> + </div> + </div> + <div class="d-flex w-100 flex-column align-items-end"> + <div class="p-2 rounded owevent_track_suggestion_next position-relative"> + <div class="text-white text-right owevent_track_suggestion_close_wrapper"> + <i class="fa fa-remove owevent_track_suggestion_close position-absolute"/> + </div> + <span class="text-white">Up Next:</span> + <span class="text-primary font-weight-bold pr-4" t-esc="widget.suggestion.name"/> + <div class="text-white owevent_track_suggestion_timer_text_wrapper"> + <span>Starts in</span> + <span class="owevent_track_suggestion_timer_text">30</span> + </div> + </div> + </div> + </div> +</div> + +</templates> |
