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