diff --git a/src/Umbraco.Core/Media/IEmbedProvider.cs b/src/Umbraco.Core/Media/IEmbedProvider.cs index 62faa45563..99b162e0b7 100644 --- a/src/Umbraco.Core/Media/IEmbedProvider.cs +++ b/src/Umbraco.Core/Media/IEmbedProvider.cs @@ -1,8 +1,24 @@ -namespace Umbraco.Core.Media +using System.Collections.Generic; + +namespace Umbraco.Core.Media { public interface IEmbedProvider { - bool SupportsDimensions { get; } + /// + /// The OEmbed API Endpoint + /// + string ApiEndpoint { get; } + + /// + /// A string array of Regex patterns to match against the pasted OEmbed URL + /// + string[] UrlSchemeRegex { get; } + + /// + /// A collection of querystring request parameters to append to the API Url + /// + /// ?key=value&key2=value2 + Dictionary RequestParams { get; } string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0); } diff --git a/src/Umbraco.Core/Media/IEmbedSettingProvider.cs b/src/Umbraco.Core/Media/IEmbedSettingProvider.cs deleted file mode 100644 index b9ba611100..0000000000 --- a/src/Umbraco.Core/Media/IEmbedSettingProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Xml; - -namespace Umbraco.Core.Media -{ - public interface IEmbedSettingProvider - { - object GetSetting(XmlNode settingNode); - } -} diff --git a/src/Umbraco.Core/Media/Result.cs b/src/Umbraco.Core/Media/OEmbedResult.cs similarity index 53% rename from src/Umbraco.Core/Media/Result.cs rename to src/Umbraco.Core/Media/OEmbedResult.cs index a8683d03d5..bed07d9b5e 100644 --- a/src/Umbraco.Core/Media/Result.cs +++ b/src/Umbraco.Core/Media/OEmbedResult.cs @@ -1,10 +1,8 @@ namespace Umbraco.Core.Media { - - // TODO: Could definitely have done with a better name - public class Result + public class OEmbedResult { - public Status Status { get; set; } + public OEmbedStatus OEmbedStatus { get; set; } public bool SupportsDimensions { get; set; } public string Markup { get; set; } } diff --git a/src/Umbraco.Core/Media/Status.cs b/src/Umbraco.Core/Media/OEmbedStatus.cs similarity index 55% rename from src/Umbraco.Core/Media/Status.cs rename to src/Umbraco.Core/Media/OEmbedStatus.cs index abbcca97da..0f1f22b0e2 100644 --- a/src/Umbraco.Core/Media/Status.cs +++ b/src/Umbraco.Core/Media/OEmbedStatus.cs @@ -1,8 +1,6 @@ namespace Umbraco.Core.Media { - - //NOTE: Could definitely have done with a better name - public enum Status + public enum OEmbedStatus { NotSupported, Error, diff --git a/src/Umbraco.Core/Media/ProviderSetting.cs b/src/Umbraco.Core/Media/ProviderSetting.cs deleted file mode 100644 index 9fef5efabf..0000000000 --- a/src/Umbraco.Core/Media/ProviderSetting.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Umbraco.Core.Media -{ - public class ProviderSetting : Attribute - { - } -} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 242b4f67bc..b327a9281d 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -650,10 +650,8 @@ - - - - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js index fb66552731..06a5f028ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js @@ -54,21 +54,22 @@ $scope.model.embed.preview = ""; - switch (response.data.Status) { + + switch (response.data.OEmbedStatus) { case 0: - //not supported - $scope.model.embed.info = "Not supported"; - break; + //not supported + $scope.model.embed.info = "Not supported"; + break; case 1: - //error - $scope.model.embed.info = "Could not embed media - please ensure the URL is valid"; - break; + //error + $scope.model.embed.info = "Could not embed media - please ensure the URL is valid"; + break; case 2: - $scope.model.embed.preview = response.data.Markup; - vm.trustedPreview = $sce.trustAsHtml(response.data.Markup); - $scope.model.embed.supportsDimensions = response.data.SupportsDimensions; - $scope.model.embed.success = true; - break; + $scope.model.embed.preview = response.data.Markup; + vm.trustedPreview = $sce.trustAsHtml(response.data.Markup); + $scope.model.embed.supportsDimensions = response.data.SupportsDimensions; + $scope.model.embed.success = true; + break; } }, function() { $scope.model.embed.supportsDimensions = false; diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 38f43f344f..e0660f8f12 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -178,9 +178,6 @@ Designer - - EmbeddedMedia.config - Designer @@ -300,7 +297,6 @@ Designer - diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config deleted file mode 100644 index 442493e3d6..0000000000 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - json - - - - - - - - - - - - - - - - - - - - 1 - xml - https - - - - - - - - - - - - - - xml - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/config/EmbeddedMedia.config b/src/Umbraco.Web.UI/config/EmbeddedMedia.config deleted file mode 100644 index c466b14f1c..0000000000 --- a/src/Umbraco.Web.UI/config/EmbeddedMedia.config +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - json - - - - - - - - - - - - - - - - - - - - 1 - xml - https - - - - - - - - - - - - - - xml - - - - - - - - xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index 6039d97a72..4302cdaeee 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -6,6 +6,7 @@ using Umbraco.Web.ContentApps; using Umbraco.Web.Dashboards; using Umbraco.Web.Editors; using Umbraco.Web.HealthCheck; +using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; @@ -101,6 +102,13 @@ namespace Umbraco.Web public static DashboardCollectionBuilder Dashboards(this Composition composition) => composition.WithCollectionBuilder(); + /// + /// Gets the backoffice OEmbed Providers collection builder. + /// + /// The composition. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this Composition composition) + => composition.WithCollectionBuilder(); + #endregion #region Uniques diff --git a/src/Umbraco.Web/Media/EmbedProviders/AbstractProvider.cs b/src/Umbraco.Web/Media/EmbedProviders/AbstractProvider.cs deleted file mode 100644 index 32f9f5c5c9..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/AbstractProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Umbraco.Core.Media; - -namespace Umbraco.Web.Media.EmbedProviders -{ - public abstract class AbstractProvider : IEmbedProvider - { - public virtual bool SupportsDimensions - { - get { return true; } - } - - public abstract string GetMarkup(string url, int maxWidth, int maxHeight); - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs b/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs new file mode 100644 index 0000000000..78ea0b8662 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/DailyMotion.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class DailyMotion : EmbedProviderBase + { + public override string ApiEndpoint => "https://www.dailymotion.com/services/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"dailymotion.com/video/.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=xml + {"format", "xml"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs b/src/Umbraco.Web/Media/EmbedProviders/EmbedProviderBase.cs similarity index 73% rename from src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs rename to src/Umbraco.Web/Media/EmbedProviders/EmbedProviderBase.cs index c73e732268..9e34815def 100644 --- a/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs +++ b/src/Umbraco.Web/Media/EmbedProviders/EmbedProviderBase.cs @@ -1,46 +1,39 @@ -using System; -using System.Text; -using System.Xml; +using Newtonsoft.Json; +using System; using System.Collections.Generic; -using System.Net; +using System.Linq; using System.Net.Http; +using System.Text; using System.Web; -using Newtonsoft.Json; +using System.Xml; using Umbraco.Core.Media; namespace Umbraco.Web.Media.EmbedProviders { - // TODO: Make all Http calls async - - public abstract class AbstractOEmbedProvider : IEmbedProvider + public abstract class EmbedProviderBase : IEmbedProvider { private static HttpClient _httpClient; - public virtual bool SupportsDimensions - { - get { return true; } - } + public abstract string ApiEndpoint { get; } - [ProviderSetting] - public string APIEndpoint { get; set; } + public abstract string[] UrlSchemeRegex { get; } - [ProviderSetting] - public Dictionary RequestParams { get; set; } + public abstract Dictionary RequestParams { get; } + + public abstract string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0); - public abstract string GetMarkup(string url, int maxWidth, int maxHeight); - - public virtual string BuildFullUrl(string url, int maxWidth, int maxHeight) + public virtual string GetEmbedProviderUrl(string url, int maxWidth, int maxHeight) { if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute) == false) throw new ArgumentException("Not a valid Url"); var fullUrl = new StringBuilder(); - fullUrl.Append(APIEndpoint); + fullUrl.Append(ApiEndpoint); fullUrl.Append("?url=" + HttpUtility.UrlEncode(url)); - foreach (var p in RequestParams) - fullUrl.Append(string.Format("&{0}={1}", p.Key, p.Value)); + foreach (var param in RequestParams) + fullUrl.Append($"&{param.Key}={param.Value}"); if (maxWidth > 0) fullUrl.Append("&maxwidth=" + maxWidth); @@ -50,7 +43,7 @@ namespace Umbraco.Web.Media.EmbedProviders return fullUrl.ToString(); } - + public virtual string DownloadResponse(string url) { if (_httpClient == null) @@ -83,6 +76,5 @@ namespace Umbraco.Web.Media.EmbedProviders var selectSingleNode = doc.SelectSingleNode(property); return selectSingleNode != null ? selectSingleNode.InnerText : string.Empty; } - } -} +}; diff --git a/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollection.cs b/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollection.cs new file mode 100644 index 0000000000..88a317c545 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollection.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Umbraco.Core.Composing; +using Umbraco.Core.Media; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class EmbedProvidersCollection : BuilderCollectionBase + { + public EmbedProvidersCollection(IEnumerable items) + : base(items) + { } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs b/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs new file mode 100644 index 0000000000..0c6ea7a3e3 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.Composing; +using Umbraco.Core.Media; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class EmbedProvidersCollectionBuilder : OrderedCollectionBuilderBase + { + protected override EmbedProvidersCollectionBuilder This => this; + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Flickr.cs b/src/Umbraco.Web/Media/EmbedProviders/Flickr.cs new file mode 100644 index 0000000000..2ce014c639 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Flickr.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Web; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Flickr : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.flickr.com/services/oembed/"; + + public override string[] UrlSchemeRegex => new string[] + { + @"flickr.com\/photos\/*", + @"flic.kr\/p\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + var imageUrl = GetXmlProperty(xmlDocument, "/oembed/url"); + var imageWidth = GetXmlProperty(xmlDocument, "/oembed/width"); + var imageHeight = GetXmlProperty(xmlDocument, "/oembed/height"); + var imageTitle = GetXmlProperty(xmlDocument, "/oembed/title"); + + return string.Format("\"{3}\"", imageUrl, imageWidth, imageHeight, HttpUtility.HtmlEncode(imageTitle)); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/GettyImages.cs b/src/Umbraco.Web/Media/EmbedProviders/GettyImages.cs new file mode 100644 index 0000000000..34b383614d --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/GettyImages.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class GettyImages : EmbedProviderBase + { + public override string ApiEndpoint => "http://embed.gettyimages.com/oembed"; + + //http://gty.im/74917285 + //http://www.gettyimages.com/detail/74917285 + public override string[] UrlSchemeRegex => new string[] + { + @"gty\.im/*", + @"gettyimages.com\/detail\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs b/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs new file mode 100644 index 0000000000..150439832a --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Hulu.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Hulu : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.hulu.com/api/oembed.json"; + + public override string[] UrlSchemeRegex => new string[] + { + @"hulu.com/watch/.*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Instagram.cs b/src/Umbraco.Web/Media/EmbedProviders/Instagram.cs new file mode 100644 index 0000000000..1862d77cad --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Instagram.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Instagram : EmbedProviderBase + { + public override string ApiEndpoint => "http://api.instagram.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"instagram.com\/p\/*", + @"instagr.am\/p\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs b/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs new file mode 100644 index 0000000000..2b33473453 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Issuu.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Issuu : EmbedProviderBase + { + public override string ApiEndpoint => "https://issuu.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"issuu.com/.*/docs/.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=xml + {"format", "xml"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Kickstarter.cs b/src/Umbraco.Web/Media/EmbedProviders/Kickstarter.cs new file mode 100644 index 0000000000..4de45ae2e3 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Kickstarter.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Kickstarter : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.kickstarter.com/services/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"kickstarter\.com/projects/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/OEmbedJson.cs b/src/Umbraco.Web/Media/EmbedProviders/OEmbedJson.cs deleted file mode 100644 index 161294be76..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/OEmbedJson.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Umbraco.Web.Media.EmbedProviders -{ - public class OEmbedJson : AbstractOEmbedProvider - { - public override string GetMarkup(string url, int maxWidth, int maxHeight) - { - string requestUrl = BuildFullUrl(url, maxWidth, maxHeight); - - var jsonResponse = GetJsonResponse(requestUrl); - return jsonResponse.GetHtml(); - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/OEmbedPhoto.cs b/src/Umbraco.Web/Media/EmbedProviders/OEmbedPhoto.cs deleted file mode 100644 index 26dbf38d31..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/OEmbedPhoto.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Web; -using System.Xml; - -namespace Umbraco.Web.Media.EmbedProviders -{ - public class OEmbedPhoto : AbstractOEmbedProvider - { - public override string GetMarkup(string url, int maxWidth, int maxHeight) - { - string requestUrl = BuildFullUrl(url, maxWidth, maxHeight); - - XmlDocument doc = GetXmlResponse(requestUrl); - string imageUrl = GetXmlProperty(doc, "/oembed/url"); - string imageWidth = GetXmlProperty(doc, "/oembed/width"); - string imageHeight = GetXmlProperty(doc, "/oembed/height"); - string imageTitle = GetXmlProperty(doc, "/oembed/title"); - - return string.Format("\"{3}\"", - imageUrl, imageWidth, imageHeight, HttpUtility.HtmlEncode(imageTitle)); - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/OEmbedResponse.cs b/src/Umbraco.Web/Media/EmbedProviders/OEmbedResponse.cs index e6577dea1f..64b18f52d3 100644 --- a/src/Umbraco.Web/Media/EmbedProviders/OEmbedResponse.cs +++ b/src/Umbraco.Web/Media/EmbedProviders/OEmbedResponse.cs @@ -31,18 +31,18 @@ namespace Umbraco.Web.Media.EmbedProviders public string ThumbnailUrl { get; set; } [JsonProperty("thumbnail_height")] - public int? ThumbnailHeight { get; set; } + public double? ThumbnailHeight { get; set; } [JsonProperty("thumbnail_width")] - public int? ThumbnailWidth { get; set; } + public double? ThumbnailWidth { get; set; } public string Html { get; set; } public string Url { get; set; } - public int? Height { get; set; } + public double? Height { get; set; } - public int? Width { get; set; } + public double? Width { get; set; } /// /// Gets the HTML. diff --git a/src/Umbraco.Web/Media/EmbedProviders/OEmbedRich.cs b/src/Umbraco.Web/Media/EmbedProviders/OEmbedRich.cs deleted file mode 100644 index 8f578ada59..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/OEmbedRich.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Umbraco.Web.Media.EmbedProviders -{ - public class OEmbedRich : OEmbedVideo - { - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/OEmbedVideo.cs b/src/Umbraco.Web/Media/EmbedProviders/OEmbedVideo.cs deleted file mode 100644 index 53bc8602d8..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/OEmbedVideo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Xml; - -namespace Umbraco.Web.Media.EmbedProviders -{ - public class OEmbedVideo : AbstractOEmbedProvider - { - public override string GetMarkup(string url, int maxWidth, int maxHeight) - { - string requestUrl = BuildFullUrl(url, maxWidth, maxHeight); - - XmlDocument doc = GetXmlResponse(requestUrl); - return GetXmlProperty(doc, "/oembed/html"); - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Settings/Dictionary.cs b/src/Umbraco.Web/Media/EmbedProviders/Settings/Dictionary.cs deleted file mode 100644 index 1c0a98205a..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/Settings/Dictionary.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Linq; -using System.Xml; -using Umbraco.Core.Media; - -namespace Umbraco.Web.Media.EmbedProviders.Settings -{ - public class Dictionary : IEmbedSettingProvider - { - public object GetSetting(XmlNode settingNode) - { - return settingNode.ChildNodes.Cast().ToDictionary(item => item.Attributes != null ? item.Attributes["name"].Value : null, item => item.InnerText); - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Settings/String.cs b/src/Umbraco.Web/Media/EmbedProviders/Settings/String.cs deleted file mode 100644 index f1d3642d79..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/Settings/String.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Xml; -using Umbraco.Core.Media; - -namespace Umbraco.Web.Media.EmbedProviders.Settings -{ - public class String : IEmbedSettingProvider - { - public object GetSetting(XmlNode settingNode) - { - return settingNode.InnerText; - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Slideshare.cs b/src/Umbraco.Web/Media/EmbedProviders/Slideshare.cs new file mode 100644 index 0000000000..6d3a010c7a --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Slideshare.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Slideshare : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.slideshare.net/api/oembed/2"; + + public override string[] UrlSchemeRegex => new string[] + { + @"slideshare\.net/" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs b/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs new file mode 100644 index 0000000000..080437a246 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/SoundCloud.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Soundcloud : EmbedProviderBase + { + public override string ApiEndpoint => "https://soundcloud.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"soundcloud.com\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Ted.cs b/src/Umbraco.Web/Media/EmbedProviders/Ted.cs new file mode 100644 index 0000000000..aa14423349 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Ted.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Ted : EmbedProviderBase + { + public override string ApiEndpoint => "http://www.ted.com/talks/oembed.xml"; + + public override string[] UrlSchemeRegex => new string[] + { + @"ted.com\/talks\/*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Twitgoo.cs b/src/Umbraco.Web/Media/EmbedProviders/Twitgoo.cs deleted file mode 100644 index 3b7816a902..0000000000 --- a/src/Umbraco.Web/Media/EmbedProviders/Twitgoo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using HtmlAgilityPack; - -namespace Umbraco.Web.Media.EmbedProviders -{ - public class Twitgoo : AbstractProvider - { - public override bool SupportsDimensions - { - get { return false; } - } - - public override string GetMarkup(string url, int maxWidth, int maxHeight) - { - var web = new HtmlWeb(); - var doc = web.Load(url); - - var img = doc.DocumentNode.SelectSingleNode("//img [@id = 'fullsize']").Attributes["src"]; - - return string.Format("", - img.Value); - } - } -} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Twitter.cs b/src/Umbraco.Web/Media/EmbedProviders/Twitter.cs new file mode 100644 index 0000000000..9286934a4d --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Twitter.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Twitter : EmbedProviderBase + { + public override string ApiEndpoint => "http://publish.twitter.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"twitter.com/.*/status/.*" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs b/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs new file mode 100644 index 0000000000..806f40a10c --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Vimeo.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class Vimeo : EmbedProviderBase + { + public override string ApiEndpoint => "https://vimeo.com/api/oembed.xml"; + + public override string[] UrlSchemeRegex => new string[] + { + @"vimeo\.com/" + }; + + public override Dictionary RequestParams => new Dictionary(); + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var xmlDocument = base.GetXmlResponse(requestUrl); + + return GetXmlProperty(xmlDocument, "/oembed/html"); + } + } +} diff --git a/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs new file mode 100644 index 0000000000..4e6f437047 --- /dev/null +++ b/src/Umbraco.Web/Media/EmbedProviders/Youtube.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Media.EmbedProviders +{ + public class YouTube : EmbedProviderBase + { + public override string ApiEndpoint => "https://www.youtube.com/oembed"; + + public override string[] UrlSchemeRegex => new string[] + { + @"youtu.be/.*", + @"youtube.com/watch.*" + }; + + public override Dictionary RequestParams => new Dictionary() + { + //ApiUrl/?format=json + {"format", "json"} + }; + + public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + var oembed = base.GetJsonResponse(requestUrl); + + return oembed.GetHtml(); + } + } +} diff --git a/src/Umbraco.Web/PropertyEditors/RteEmbedController.cs b/src/Umbraco.Web/PropertyEditors/RteEmbedController.cs index 4cebc5c829..b3498c16ae 100644 --- a/src/Umbraco.Web/PropertyEditors/RteEmbedController.cs +++ b/src/Umbraco.Web/PropertyEditors/RteEmbedController.cs @@ -1,14 +1,10 @@ using System; -using System.Linq; using System.Text.RegularExpressions; -using System.Xml; -using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Web.Editors; using Umbraco.Web.Mvc; using Umbraco.Core.Media; -using System.IO; -using Umbraco.Core.IO; +using Umbraco.Web.Media.EmbedProviders; namespace Umbraco.Web.PropertyEditors { @@ -18,60 +14,56 @@ namespace Umbraco.Web.PropertyEditors [PluginController("UmbracoApi")] public class RteEmbedController : UmbracoAuthorizedJsonController { - public Result GetEmbed(string url, int width, int height) + private EmbedProvidersCollection _embedCollection; + + public RteEmbedController(EmbedProvidersCollection embedCollection) { - var result = new Result(); + _embedCollection = embedCollection ?? throw new ArgumentNullException(nameof(embedCollection)); + } - // TODO: cache embed doc - var xmlConfig = new XmlDocument(); - xmlConfig.Load(IOHelper.GetRootDirectorySafe() + Path.DirectorySeparatorChar + "config" + Path.DirectorySeparatorChar + "EmbeddedMedia.config"); + public OEmbedResult GetEmbed(string url, int width, int height) + { + var result = new OEmbedResult(); + var foundMatch = false; + IEmbedProvider matchedProvider = null; - foreach (XmlNode node in xmlConfig.SelectNodes("//provider")) + foreach (var provider in _embedCollection) { - var regexPattern = new Regex(node.SelectSingleNode("./urlShemeRegex").InnerText, RegexOptions.IgnoreCase); - - if (regexPattern.IsMatch(url)) + //Url Scheme Regex is an array of possible regex patterns to match against the URL + foreach(var urlPattern in provider.UrlSchemeRegex) { - var prov = (IEmbedProvider)Activator.CreateInstance(Type.GetType(node.Attributes["type"].Value)); - - if (node.Attributes["supportsDimensions"] != null) - result.SupportsDimensions = node.Attributes["supportsDimensions"].Value == "True"; - else - result.SupportsDimensions = prov.SupportsDimensions; - - var settings = node.ChildNodes.Cast().ToDictionary(settingNode => settingNode.Name); - - foreach (var prop in prov.GetType().GetProperties().Where(prop => prop.IsDefined(typeof(ProviderSetting), true))) + var regexPattern = new Regex(urlPattern, RegexOptions.IgnoreCase); + if (regexPattern.IsMatch(url)) { - - if (settings.Any(s => s.Key.ToLower() == prop.Name.ToLower())) - { - var setting = settings.FirstOrDefault(s => s.Key.ToLower() == prop.Name.ToLower()).Value; - var settingType = typeof(Media.EmbedProviders.Settings.String); - - if (setting.Attributes["type"] != null) - settingType = Type.GetType(setting.Attributes["type"].Value); - - var settingProv = (IEmbedSettingProvider)Activator.CreateInstance(settingType); - prop.SetValue(prov, settingProv.GetSetting(settings.FirstOrDefault(s => s.Key.ToLower() == prop.Name.ToLower()).Value), null); - } + foundMatch = true; + matchedProvider = provider; + break; } - try - { - result.Markup = prov.GetMarkup(url, width, height); - result.Status = Status.Success; - } - catch(Exception ex) - { - Logger.Error(ex, "Error embedding url {Url} - width: {Width} height: {Height}", url, width, height); - result.Status = Status.Error; - } - - return result; } + + if (foundMatch) + break; + } + + if(foundMatch == false) + { + //No matches return/ exit + result.OEmbedStatus = OEmbedStatus.NotSupported; + return result; + } + + try + { + result.SupportsDimensions = true; + result.Markup = matchedProvider.GetMarkup(url, width, height); + result.OEmbedStatus = OEmbedStatus.Success; + } + catch(Exception ex) + { + Logger.Error(ex, "Error embedding url {Url} - width: {Width} height: {Height}", url, width, height); + result.OEmbedStatus = OEmbedStatus.Error; } - result.Status = Status.NotSupported; return result; } } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 4070ee9ece..b81f2db486 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -23,6 +23,7 @@ using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; +using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; @@ -212,6 +213,24 @@ namespace Umbraco.Web.Runtime // and will filter out those that are not attributed with TreeAttribute composition.WithCollectionBuilder() .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); + + // register OEmbed providers - no type scanning - all explicit opt-in of adding types + // note: IEmbedProvider is not IDiscoverable - think about it if going for type scanning + composition.WithCollectionBuilder() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); } } } + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 709d938ba4..63836931a7 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -143,6 +143,23 @@ + + + + + + + + + + + + + + + + + @@ -657,9 +674,6 @@ - - - @@ -1071,13 +1085,6 @@ - - - - - - -