PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/BlogEngine/BlogEngine.NET/App_Code/Extensions/MediaElementPlayer.cs

#
C# | 313 lines | 235 code | 60 blank | 18 comment | 36 complexity | cb1527e92f98f0adb47cff7b2d399359 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. /*
  2. Author: John Dyer (http://johndyer.name/)
  3. Player: MediaElementJS (http://mediaelementjs.com/)
  4. */
  5. using System;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Web;
  11. using System.Web.UI.HtmlControls;
  12. using BlogEngine.Core;
  13. using BlogEngine.Core.Web.Controls;
  14. using BlogEngine.Core.Web.Extensions;
  15. using Page=System.Web.UI.Page;
  16. /// <summary>
  17. /// Adds a HTML5 video/audio player to posts with Flash/Silverlight fallbacks
  18. /// </summary>
  19. [Extension("HTML5 Video/Audio Player", "1.5", @"<a href=""http://johndyer.me/"">John Dyer</a>")]
  20. public class MediaElementPlayer
  21. {
  22. #region Private members
  23. private const string _extensionName = "MediaElementPlayer";
  24. private static readonly object _syncRoot = new object();
  25. static protected Dictionary<Guid, ExtensionSettings> _blogsSettings = new Dictionary<Guid, ExtensionSettings>();
  26. #endregion
  27. private const int _widthDefault = 480;
  28. private const int _heightDefault = 360;
  29. private const bool _enableAutoSize = false;
  30. private const string _folderDefault = "media";
  31. /// <summary>
  32. /// Adds a Flash video player to the post.
  33. /// </summary>
  34. static MediaElementPlayer()
  35. {
  36. Post.Serving += Publishable_Serving;
  37. BlogEngine.Core.Page.Serving += Publishable_Serving;
  38. InitSettings();
  39. }
  40. private static void InitSettings()
  41. {
  42. // call Settings getter so default settings are loaded on application start.
  43. var s = Settings;
  44. }
  45. private static ExtensionSettings Settings
  46. {
  47. get
  48. {
  49. Guid blogId = Blog.CurrentInstance.Id;
  50. if (!_blogsSettings.ContainsKey(blogId))
  51. {
  52. lock (_syncRoot)
  53. {
  54. if (!_blogsSettings.ContainsKey(blogId))
  55. {
  56. _blogsSettings[blogId] = LoadExtensionSettingsForBlogInstance();
  57. }
  58. }
  59. }
  60. return _blogsSettings[blogId];
  61. }
  62. }
  63. private static ExtensionSettings LoadExtensionSettingsForBlogInstance()
  64. {
  65. ExtensionSettings initialSettings = new ExtensionSettings(_extensionName);
  66. initialSettings.Help = @"
  67. <p>Build on <a href=""http://mediaelement.js.com/"">MediaElement.js</a>, the HTML5 video/audio player.</p>
  68. <ol>
  69. <li>Upload media files to your /media/ folder</li>
  70. <li>Add short code to your media: [video src=""myfile.mp4""] for video and [audio src=""myfile.mp3""] for audio</li>
  71. <li>Customize with the following parameters:
  72. <ul>
  73. <li><b>width</b>: The exact width of the video</li>
  74. <li><b>height</b>: The exact height of the video</li>
  75. <li><b>autoplay</b>: Plays the video as soon as the webpage loads</li>
  76. </ul>
  77. </li>
  78. <li>You can also specify multiple file formats and codecs
  79. <ul>
  80. <li><b>mp4</b>: H.264 encoded MP4 file</li>
  81. <li><b>webm</b>: VP8/WebM encoded file</li>
  82. <li><b>ogg</b>: Theora/Vorbis encoded file</li>
  83. </ul>
  84. </li>
  85. </ol>
  86. <p>A complete example:<br />
  87. [code mp4=""myfile.mp4"" webm=""myfile.webm"" ogg=""myfile.ogg"" width=""480"" height=""360""]
  88. </p>
  89. <p>Supported formats</p>
  90. <ul>
  91. <li><b>MP4/MP3</b>: Native HTML5 for IE9, Safari, Chrome; Flash in IE8, Firefox, Opera</li>
  92. <li><b>WebM</b>: HTML5 for IE9, Chrome, Firefox, Opera; Flash in IE8 (coming in Flash 11)</li>
  93. <li><b>FLV</b>: Flash fallback</li>
  94. <li><b>WMV/WMA</b>: Silverlight fallback</li>
  95. </ul>
  96. ";
  97. initialSettings.IsScalar = true;
  98. initialSettings.AddParameter("width", "Default Width");
  99. initialSettings.AddValue("width", _widthDefault.ToString());
  100. initialSettings.AddParameter("height", "Default Height");
  101. initialSettings.AddValue("height", _heightDefault.ToString());
  102. initialSettings.AddParameter("folder", "Folder for Media (MP4, MP3, WMV, Ogg, WebM, etc.)");
  103. initialSettings.AddValue("folder", _folderDefault);
  104. return ExtensionManager.InitSettings(_extensionName, initialSettings);
  105. }
  106. private static void Publishable_Serving(object sender, ServingEventArgs e)
  107. {
  108. if (!ExtensionManager.ExtensionEnabled("MediaElementPlayer"))
  109. return;
  110. if (e.Location == ServingLocation.PostList || e.Location == ServingLocation.SinglePost || e.Location == ServingLocation.Feed || e.Location == ServingLocation.SinglePage) {
  111. HttpContext context = HttpContext.Current;
  112. string regex = @"(video|audio)";
  113. List<ShortCode> shortCodes = GetShortCodes(e.Body, regex, true);
  114. if (shortCodes.Count == 0)
  115. return;
  116. ProcessMediaTags(e, shortCodes);
  117. // this won't happen on feeds
  118. if (context.CurrentHandler is Page) {
  119. Page page = (Page)context.CurrentHandler;
  120. AddHeader(page);
  121. AddFooter(page);
  122. }
  123. }
  124. }
  125. private static void AddHeader(Page page)
  126. {
  127. string path = Utils.ApplicationRelativeWebRoot + "Scripts/mediaelement/";
  128. AddJavaScript(path + "mediaelement.min.js", page);
  129. AddJavaScript(path + "mediaelementplayer.min.js", page);
  130. AddStylesheet(path + "mediaelementplayer.min.css", page);
  131. }
  132. private static void AddJavaScript(string src, Page page)
  133. {
  134. HtmlGenericControl script = new HtmlGenericControl("script");
  135. script.Attributes["type"] = "text/javascript";
  136. script.Attributes["src"] = src;
  137. page.Header.Controls.Add(script);
  138. }
  139. private static void AddStylesheet(string href, Page page)
  140. {
  141. HtmlLink css = new HtmlLink();
  142. css.Attributes["type"] = "text/css";
  143. css.Attributes["rel"] = "stylesheet";
  144. css.Attributes["href"] = href;
  145. page.Header.Controls.Add(css);
  146. }
  147. private static void AddFooter(Page page)
  148. {
  149. int width = 0;
  150. int height = 0;
  151. if (!Int32.TryParse(Settings.GetSingleValue("width"), out width))
  152. width = _widthDefault;
  153. if (!Int32.TryParse(Settings.GetSingleValue("height"), out height))
  154. height = _heightDefault;
  155. string startupScript = @"
  156. <script type=""text/javascript"">
  157. jQuery(document).ready(function($) {
  158. $('audio.mep, video.mep').mediaelementplayer({defaultVideoWidth:" + width.ToString() + ", defaultVideoHeight:" + height.ToString() + @"});
  159. });
  160. </script>
  161. ";
  162. page.ClientScript.RegisterStartupScript(page.GetType(), _extensionName, startupScript, false);
  163. }
  164. private static void ProcessMediaTags(ServingEventArgs e, List<ShortCode> shortCodes)
  165. {
  166. // path to media
  167. string folder = Settings.GetSingleValue("folder");
  168. string path = Utils.RelativeWebRoot + folder.TrimEnd(new char[] {'/'}) + "/";
  169. // override for feed
  170. if (e.Location == ServingLocation.Feed) {
  171. path = Utils.AbsoluteWebRoot + folder.TrimEnd(new char[] { '/' }) + "/";
  172. }
  173. // do replacement for media
  174. foreach (ShortCode sc in shortCodes)
  175. {
  176. string tagName = sc.TagName;
  177. string src = sc.GetAttributeValue("src", "");
  178. string w = sc.GetAttributeValue("width", "");
  179. string h = sc.GetAttributeValue("height", "");
  180. string mp4 = sc.GetAttributeValue("mp4", "");
  181. string mp3 = sc.GetAttributeValue("mp3", "");
  182. string webm = sc.GetAttributeValue("webm", "");
  183. string ogg = sc.GetAttributeValue("ogg", "");
  184. string poster = sc.GetAttributeValue("poster", "");
  185. string autoplay = sc.GetAttributeValue("autoplay", "");
  186. string preload = sc.GetAttributeValue("preload", "");
  187. string code =
  188. "<" + tagName + " class=\"mep\" controls=\"controls\"" + ((src != "") ? " src=\"" + ((src.IndexOf("http") == 0) ? "" : path) + src + "\"" : "") + ((poster != "") ? " poster=\"" + ((poster.IndexOf("http") == 0) ? "" : path) + poster + "\"" : "") + ((w != "") ? " width=\"" + w + "\"" : "") + ((h != "") ? " height=\"" + h + "\"" : "") + ((autoplay != "") ? " autoplay=\"autoplay\"" : "") + ((preload != "") ? " preload=\"" + preload + "\"" : "") + ">" +
  189. ((mp4 != "") ? "<source src=\"" + ((mp4.IndexOf("http") == 0) ? "" : path) + mp4 + "\" type=\"video/mp4\" />" : "") +
  190. ((mp3 != "") ? "<source src=\"" +((mp3.IndexOf("http") == 0) ? "" : path) + mp3 + "\" type=\"audio/mp3\" />" : "") +
  191. ((webm != "") ? "<source src=\"" + ((webm.IndexOf("http") == 0) ? "" : path) + webm + "\" type=\"video/webm\" />" : "") +
  192. ((ogg != "") ? "<source src=\"" + ((ogg.IndexOf("http") == 0) ? "" : path) + ogg + "\" type=\"video/ogg\" />" : "") +
  193. "</" + tagName + ">";
  194. e.Body = e.Body.Replace(sc.Text, code);
  195. }
  196. }
  197. public static List<ShortCode> GetShortCodes(string input)
  198. {
  199. return GetShortCodes(input, true);
  200. }
  201. public static List<ShortCode> GetShortCodes(string input, bool removeParagraphs)
  202. {
  203. return GetShortCodes(input, @"\w+", removeParagraphs);
  204. }
  205. public static List<ShortCode> GetShortCodes(string input, string regexMatchString, bool removeParagraphs)
  206. {
  207. List<ShortCode> shortCodes = new List<ShortCode>();
  208. // get the main tag [tag attr="value"]
  209. string find = @"\[(?<tag>" + regexMatchString + @")(?<attrs>[^\]]+)\]";
  210. if (removeParagraphs) {
  211. find = @"(<p>[\s\n]?)+" + find + @"([\s\n]?</p>)+";
  212. }
  213. MatchCollection matches = Regex.Matches(input, find);
  214. foreach (Match match in matches) {
  215. string tagName = match.Groups["tag"].Value;
  216. string attributes = match.Groups["attrs"].Value;
  217. ShortCode sc = new ShortCode(tagName, match.Value);
  218. // parse the attributes
  219. // attr="value"
  220. MatchCollection attrMatches = Regex.Matches(attributes, @"(?<attr>\w+)=""(?<val>[^""]+)""");
  221. foreach (Match attrMatch in attrMatches) {
  222. sc.Attributes.Add(attrMatch.Groups["attr"].Value, attrMatch.Groups["val"].Value);
  223. }
  224. shortCodes.Add(sc);
  225. }
  226. return shortCodes;
  227. }
  228. public class ShortCode
  229. {
  230. public ShortCode(): this("","") {
  231. }
  232. public ShortCode(string tagName, string text) {
  233. _tagName = tagName;
  234. _text = text;
  235. _attributes = new Dictionary<string, string>();
  236. }
  237. private string _tagName;
  238. private string _text;
  239. private Dictionary<string, string> _attributes;
  240. public string TagName { get { return _tagName; } set { _tagName = value; } }
  241. public string Text { get { return _text; } set { _text = value; } }
  242. public Dictionary<string, string> Attributes { get { return _attributes; } set { _attributes = value; } }
  243. public string GetAttributeValue(string attributeName, string defaultValue) {
  244. if (Attributes.ContainsKey(attributeName))
  245. return Attributes[attributeName];
  246. else
  247. return defaultValue;
  248. }
  249. }
  250. }