/// <summary> /// Renders the shortcode contents to the writer. /// </summary> /// <param name="parms">The parameters that will be used to construct the content.</param> /// <param name="currentPerson">The current person.</param> /// <param name="result">The writer that output should be written to.</param> internal static void RenderToWriter(Dictionary <string, string> parms, Person currentPerson, TextWriter result) { var options = new MediaPlayerOptions { Autoplay = parms[ParameterKeys.AutoPlay].AsBoolean(), Autopause = parms[ParameterKeys.AutoPause].AsBoolean(true), ClickToPlay = parms[ParameterKeys.ClickToPlay].AsBoolean(true), Controls = parms[ParameterKeys.Controls], Debug = parms[ParameterKeys.Debug].AsBoolean(), HideControls = parms[ParameterKeys.HideControls].AsBoolean(true), MediaUrl = parms[ParameterKeys.Source], Muted = parms[ParameterKeys.Muted].AsBoolean(), PosterUrl = parms[ParameterKeys.Thumbnail], RelatedEntityId = parms[ParameterKeys.RelatedEntityId].AsIntegerOrNull(), RelatedEntityTypeId = parms[ParameterKeys.RelatedEntityTypeId].AsIntegerOrNull(), SeekTime = parms[ParameterKeys.SeekTime].AsIntegerOrNull() ?? 10, TrackProgress = true, Type = parms[ParameterKeys.Type], Volume = parms[ParameterKeys.Volume].AsDoubleOrNull() ?? 1.0, WriteInteraction = currentPerson != null ? parms[ParameterKeys.TrackSession].AsBoolean(true) : parms[ParameterKeys.TrackAnonymousSession].AsBoolean(true) }; // Get the rest of the parameters in easy to access variables. var mediaId = parms[ParameterKeys.Media].AsIntegerOrNull(); var mediaGuid = parms[ParameterKeys.Media].AsGuidOrNull(); var autoResumeInDays = parms[ParameterKeys.AutoResumeInDays].AsIntegerOrNull() ?? 7; var combinePlayStatisticsInDays = parms[ParameterKeys.CombinePlayStatisticsInDays].AsIntegerOrNull() ?? 7; var primaryColor = parms[ParameterKeys.PrimaryColor]; var width = parms[ParameterKeys.Width]; options.UpdateValuesFromMedia(mediaId, mediaGuid, autoResumeInDays, combinePlayStatisticsInDays, currentPerson); var elementId = $"mediaplayer_{Guid.NewGuid()}"; // Construct the CSS style for this media player. var style = $"--plyr-color-main: {( primaryColor.IsNotNullOrWhiteSpace() ? primaryColor : "var(--brand-primary)" )};"; style += (width.IsNotNullOrWhiteSpace() ? $" width:{width}" : ""); // Construct the JavaScript to initialize the player. var script = $@"<script> (function() {{ new Rock.UI.MediaPlayer(""#{elementId}"", {options.ToJson( indentOutput: false )}); }})(); </script>"; result.WriteLine($"<div id=\"{elementId}\" style=\"{style}\"></div>"); result.WriteLine(script); // If we have a RockPage related to the current request then // register all the JS and CSS links we need. if (HttpContext.Current != null && HttpContext.Current.Handler is System.Web.UI.Page page) { Rock.Web.UI.Controls.MediaPlayer.AddLinksForMediaToPage(options.MediaUrl, page); } }
internal static unsafe bool Invoke(IntPtr obj, MediaSource MediaSource, MediaPlayerOptions Options) { long *p = stackalloc long[] { 0L, 0L, 0L, 0L, 0L, 0L }; byte *b = (byte *)p; *((IntPtr *)(b + 0)) = MediaSource; *((MediaPlayerOptions *)(b + 8)) = Options; Main.GetProcessEvent(obj, OpenSourceWithOptions_ptr, new IntPtr(p));; return(*((bool *)(b + 36))); } }
///<summary>Open the specified media source with supplied options applied.</summary> ///<remarks> ///A return value of true indicates that the player will attempt to open ///the media, but it may fail to do so later for other reasons, i.e. if ///a connection to the media server timed out. Use the OnMediaOpened and ///OnMediaOpenFailed delegates to detect if and when the media is ready! /// ///@param MediaSource The media source to open. ///@param Options The media player options to apply. ///@return true if the source will be opened, false otherwise. ///@see Close, OpenFile, OpenPlaylist, OpenPlaylistIndex, OpenUrl, Reopen ///</remarks> public bool OpenSourceWithOptions(MediaSource MediaSource, MediaPlayerOptions Options) => MediaPlayer_methods.OpenSourceWithOptions_method.Invoke(ObjPointer, MediaSource, Options);
/// <summary> /// Updates the options from a <see cref="MediaElement"/>. If one is /// not found then no changes are made. /// </summary> /// <param name="options">The options to be updated.</param> /// <param name="mediaElementId">The media element identifier.</param> /// <param name="mediaElementGuid">The media element unique identifier.</param> /// <param name="autoResumeInDays">The number of days back to look for an existing watch map to auto-resume from. Pass -1 to mean forever or 0 to disable.</param> /// <param name="combinePlayStatisticsInDays">The number of days back to look for an existing interaction to be updated. Pass -1 to mean forever or 0 to disable.</param> /// <param name="currentPerson">The person to use when searching for existing interactions.</param> internal static void UpdateValuesFromMedia(this MediaPlayerOptions options, int?mediaElementId, Guid?mediaElementGuid, int autoResumeInDays, int combinePlayStatisticsInDays, Person currentPerson) { if (!mediaElementId.HasValue && !mediaElementGuid.HasValue) { return; } using (var rockContext = new RockContext()) { var mediaElementService = new MediaElementService(rockContext); var interactionService = new InteractionService(rockContext); var mediaEventsChannelGuid = Rock.SystemGuid.InteractionChannel.MEDIA_EVENTS.AsGuid(); var now = RockDateTime.Now; MediaElement mediaElement = null; // Load the media element by either Id or Guid value. if (mediaElementId.HasValue) { mediaElement = mediaElementService.Get(mediaElementId.Value); } else { mediaElement = mediaElementService.Get(mediaElementGuid.Value); } // No media found means we don't have anything to do. if (mediaElement == null) { return; } options.MediaUrl = mediaElement.DefaultFileUrl; options.MediaElementGuid = mediaElement.Guid; // Let the users value override the default thumbnail. if (options.PosterUrl.IsNullOrWhiteSpace()) { options.PosterUrl = mediaElement.DefaultThumbnailUrl; } // Check if either autoResumeInDays or combinePlayStatisticsInDays // are enabled. If not we are done. if (autoResumeInDays == 0 && combinePlayStatisticsInDays == 0) { return; } // If we don't have a person, then we can't get interactions. if (currentPerson == null) { return; } // Build a query to find Interactions for this person having // previously watched this media element. var interactionQry = interactionService.Queryable() .Where(i => i.InteractionComponent.InteractionChannel.Guid == mediaEventsChannelGuid && i.InteractionComponent.EntityId == mediaElement.Id && i.PersonAlias.PersonId == currentPerson.Id); // A negative value means "forever". int daysBack = Math.Max(autoResumeInDays >= 0 ? autoResumeInDays : int.MaxValue, combinePlayStatisticsInDays >= 0 ? combinePlayStatisticsInDays : int.MaxValue); // A value of MaxValue means "forever" now so we don't need // to filter on it. if (daysBack != int.MaxValue) { var limitDateTime = now.AddDays(-daysBack); interactionQry = interactionQry.Where(i => i.InteractionDateTime >= limitDateTime); } // Look for the most recent Interaction. var interaction = interactionQry.OrderByDescending(i => i.InteractionDateTime) .Select(i => new { i.Guid, i.InteractionDateTime, i.InteractionData }) .FirstOrDefault(); // If we didn't find any interaction then we are done. if (interaction == null) { return; } // Check if this interaction is within our auto-resume window. if (autoResumeInDays != 0) { if (autoResumeInDays < 0 || interaction.InteractionDateTime >= now.AddDays(-autoResumeInDays)) { options.ResumePlaying = true; var data = interaction.InteractionData.FromJsonOrNull <MediaWatchedInteractionData>(); options.Map = data?.WatchMap; } } // Check if this interaction is within our combine window. if (combinePlayStatisticsInDays != 0) { if (combinePlayStatisticsInDays < 0 || interaction.InteractionDateTime >= now.AddDays(-combinePlayStatisticsInDays)) { options.InteractionGuid = interaction.Guid; } } } }