How to get Video url from media picker in Umbraco - umbraco

I've media picker in my current Document Type. In that I have taken two Media picker. first for the multiple images slider and another for video.
And Content
Now I am trying to get this url in my code by given code:
var imageList = CurrentPage.productsSliderImages.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
var video = Umbraco.Media(CurrentPage.productSliderVideo);
I am getting ImageList successfully. But I am getting video null.
If I replace my video with any Image again its start working. Is there any problem with Video or other file with media picker?
Watch:
http://prntscr.com/e9wal1

To resolve a problem like this, I would recommend trying to print the raw value of the video Media Picker to the screen or inspecting it in debug mode. I like to work with the more strongly typed IPublishedContent, so I would debug with some code like this:
var videoData = Model.Content.GetPropertyValue<string>("productSliderVideo");
Normally, if you are working on a View that inherits from #inherits UmbracoTemplatePage, both Model.Content and CurrentPage will give you the data on the current page. You can work with the CurrentPage if you like working with dynamics or you can work with Model.Content to work with more strongly typed IPublishedContent models. I prefer the strongly typed version because it is a lot easier for me to debug.
Once you verify that you are getting an id back, I would check the media item that you have picked in the backoffice just as a sanity check. Make sure it matches. If it does, I would try reindexing the InternalIndexer in the Examine Index Manager. As far as I understand, Umbraco uses the internal examine indexer as a media cache. After doing all of this, I would try the below. It is the same as what you are doing above, but with the TypedMedia instead of the dynamic media. Maybe it will reveal more to you. I personally find the typed content and typed media a lot easier to debug. It might make sense to switch over to that for the sake of debugging even if you decide you want to switch back to the dynamics afterwards:
var video = Umbraco.TypedMedia(videoData);

Related

How to Let Chrome History Ignore Part of URL

As my work involves viewing many items from a website, I need to know which items have been visited and which not, so as to avoid repeated viewing.
The problem is that the URL of these items include some garbage parameters that are dynamically changing. This means the browser's history record is almost useless in identifying which items have already been viewed.
This is an example of the URL:
https://example.com/showitemdetail/?item_id=e6de72e&hitkey=true&index=234&cur_page=1&pageSize=30
Only the "item_id=e6de72e" part is useful in identifying each item. The other parameters are dynamic garbage.
My question is: how to let Chrome mark only the "example.com/showitemdetail/?item_id=e6de72e" part as visited, and ignore the rest parameters?
Please note that I do NOT want to modify the URLs, because that might alarm the website server to suspect that I am abusing their database. I want the garbage parameters to be still there, but the browser history mechanism to ignore them.
I know this is not easy. I am proposing a possible solution, but do not know whether it can be implemented. It's like this:
Step: 1) An extension background script to extract the item_id from each page I open, and then store it in a collection of strings. This collection of strings should be saved in a file somewhere.
Step: 2) Each time I open a webpage with a list of various items, the background script verifies whether each URL contains a string which matches any one in the above collection. If so, that URL would be automatically added to history. Then that item will naturally be shown as visited.
Does the logic sound OK? And if so how to implementable it by making a simple extension?
Of course, if you have other more neat solutions, I'd be very interested to learn.
Assuming that the link to the items always have the item_id, that would work, yes.
You would need the following steps:
Recording an element
content_script that adds a code to the product pages and tracks it.
On accessing the product page:
i. You can extract the current product id by checking the URL parameters (see one of these codes).
ii. You use storage api to retrieve a certain stored variable, say: visited_products. This variable you need to implement it as a Set since it's the best data type to handle unique elements.
iii. You check whether the current element is on the list with .has(). If yes, then you skip it. If all is good, it should always be new, but no harm in checking. If not, then you use add() to add the new product id (although Set will not allow you to add a repeated items, so you can skip the check and just save add it directly). Make sure you store it to Chrome.
Now you have registered a visit to a product.
Checking visited elements
You use a content_script again to be inserted on product pages or all pages if desired.
You get all the links of the page with document.querySelectorAll(). You could apply a CSS selector like: a[href*="example.com/showitemdetail/?item_id="] which would select all the links whose href contains that URL portion.
Then, you iterate the links with a for loop. On each iteration, you extract the item_id. Probably, the easiest way is: /(?:item_id=)(.*?)(?:&|$)/. This matches all characters preceded by item_id= (not captured) until it finds an & or end of the string (whichever happens first, and not captured).
With the id captured, you can check the Set of the first part with .has() to see whether it's on the list.
Now, about how to handle whether it's on the list, depends on you. You could hide visited elements. Or apply different CSS classes or style to them so you differentiate them easily.
I hope this gives you a head start. Maybe you can give it a try and, if you cannot make it work, you can open a new question with where you got stuck.
Thanks a lot, fvbuendia. After some trial and error elbow grease, I made it.
I will not post all the codes here, but will give several tips for other users' reference:
1) To get the URL of newly opened webpage and extract the IDs, use chrome.tabs.onUpdated.addListener and extractedItemId = tab.url.replace(/..../, ....);
2) Then save the IDs to storage.local, using chrome.storage.local.set and chrome.storage.local.get. The IDs should be saved to an object array.
1) and 2) should be written in the background script.
3) Each time the item list page is opened, the background calls a function in the content script, asking for all the URLs in the page. Like this:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete") {
if(tab.url.indexOf("some string typical of the item list page URL") > -1) {
chrome.tabs.executeScript(null, { code: 'getalltheurls();' });
} }
});
4) The function to be executed in content script:
function getalltheurls() {
var urls = [];
var links = document.links;
for (var i = 0; i < links.length; i++) {
if(links[i].href.indexOf("some string typical of the item list URLs") > -1) { urls.push(links[i].href);}
}
chrome.runtime.sendMessage({ urls: urls });
};
5) Background receives the URLs, then converts them to an array of IDs, using
idinlist = urls[i].replace(........)
6) Then background gets local storage, using chrome.storage.local.get, and checks if these IDs are in the stored array. If so, add the URL to history.
for (var i = 0; i < urls.length; i++) {
if (storedIDs.indexOf(idinlist) > -1 ) { chrome.history.addUrl({ url: urls[i] }); }
}

Umbraco 7 Custom Media Type Drag and Drop functionality

So just started some work with an Umbraco 7 site.
The site has a custom media type. When adding media (including by dragging and dropping) and selecting this custom type the full path/url of the file added does not appear to be stored anywhere.
I've added a listener to the MediaService.Saved event and this is firing but within this method all the information I appear to have available is the id and the name of the file rather than the file itself.
I was expecting the "umbracoFile" property to be automatically populated but that doesn't appear to be the case. [I even tried editing my custom media type to have a property with alias "umbracoFile" but that just causes the Backend to crash].
Is there anyway to get the url/path of the file or to force Umbraco to set the "umbracoFile" property?
When you perform a drag and drop operation on a Folder Browser control (used in the Media section on Folders, or in the Media Picker dialog), Umbraco inspects the file type that you are dragging onto the upload area, and based on that determines the best media type to create. By default, for any known image type (png, jpg, gif, etc.) that is the Image media type, anything else is automatically assigned to the File media type.
When you hook into the MediaService.Saved event, you have access to the object representing that file in Umbraco Media, but it's already saved as a particular file type based on the description above (this has changed a little in 7.5.9 - see the below note). If you want to enable your own media type and have it set up for drag and drop, you need to dig a bit deeper.
Take a look at this: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Editors/MediaController.cs#L626-L638
Note: This applies to very recent versions of Umbraco only, as of 7.5.9 - your mileage may vary.
You may need need to look at setting the contentTypeAlias parameter of the post data when uploading the file to your preferred Media type, which may require you to create your own version of the Folder Browser data type.
Got something working in the end thanks to Robert's answer - it's fairly hacky but appears to work so I'm going to leave it here in case it helps anyone else.
Note that it uses a depreciated event handler and reflection to set private variables so I can't recommend that anyone else use it, but it might give people an idea where to start:
public void MediaService_Creating(IMediaService sender, NewEventArgs<IMedia> e)
{
int i = 0;
Type t = e.Entity.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo field = fields.First(x => x.Name == "_contentType");
MethodInfo findMediaTypeByAlias = ApplicationContext.Current.Services.MediaService
.GetType().GetMethod("FindMediaTypeByAlias", BindingFlags.NonPublic | BindingFlags.Instance);
IMediaType mediaType = (IMediaType)findMediaTypeByAlias.Invoke(
ApplicationContext.Current.Services.MediaService,
new object[] { Constants.Conventions.MediaTypes.Image });
field.SetValue(e.Entity, mediaType);
field = fields.First(x => x.Name == "ContentTypeBase");
field.SetValue(e.Entity, mediaType);
i = e.Entity.ContentTypeId;
}
The basic premise is to change the media type to Image whilst the media type is being created. By changing it in this way any extra properties for the Image media type get added and automatically populated. If a property on the custom media type shares an alias with one of the Image media type properties (such as umbracoFile) then that properties value is automatically populated meaning that it can be used in any Saving/Saved event listeners as required.

Youtube API v3 - Related videos from specific channel

I want to get related videos only from the uploader's channel, but it looks like a search with relatedToVideoId will ignore channelId when specified.
E.g. https://www.googleapis.com/youtube/v3/search?channelId=UCgiDRy6oyLanAcFeM4-_OYA&relatedToVideoId=eWXm5ZKGXSw&part=snippet,id&type=video&maxResults=10&key={your_api_key}
And https://www.googleapis.com/youtube/v3/search?relatedToVideoId=eWXm5ZKGXSw&part=snippet,id&type=video&maxResults=10&key={your_api_key}
Will both return the same set of results.
Am I doing something wrong, or is this the intended behavior?
You're not doing anything wrong -- whether or not this is intended could only be answered by the engineering team, however. But it seems that the relatedToVideoId parameter is designed to ignore all other search filters (even 'q').
It seems logical that this is intended, as it is possibly tapping into the same algorithm that generates the related video thumbnails when a video is done playing (in other words, it's specifically used as a discovery tool for videos outside the keyword or channel relationships).
The above answer is correct, but if you still want to use this method and differentiate the channel's videos' to show yours only, you can, by doing this:
(written in jQuery, but the same concept applies to other languages)
var channelTitle = item.snippet.channelTitle;
var result = "";
if(channelTitle === "Your Channel Name")
{
// print results
$('.related-video').append(result);
$(item).show(); // show item
}
else // does not match channel name
{
$(item).hide(); // hide item
}

How to display a picture using data from ViewData.Model [as opposed taking data from a remote location using, for instance, Url.Action]

I'm doing kind of wizard application that captures information on Contacts. So, before saving to DB, all data collected during the process are kept in memory as model's properties (using serialization/deserialization). Data collected includes the uploaded picture of the contact. The last page is called "preview" where I display all the information entered during the process before saving them to the DB. On that preview page, I'd like also to display the photo of the contact on left and his information on the right.
It is easier to display picture using the following statements
<img src = ".../.../Content/MyPicture" />
<img src = "<% = Url.Action("Action", "Controller", "routevalue")%>"/>
How about if the data is not located in remote locations like in the above samples, but rather in the ViewData.Model?
By the way, my model, ContactData, has 2 properties ImageData and ImageMimeType holding data for the picture. How do I use them?
Thanks for helping
Usually, you'd store it in a session variable, and when the request for the image comes around you'll feed it whatever is in the session. There are a couple of things that need to work in order for this to function, but usually it does.
There is one more option, if the image is small, you can inline it directly into your document using a data uri, like so:
<img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
vr4MkhoXe0rZigAAAABJRU5ErkJggg==" />
(example is stolen from wikipedia, paste uri into your location bar, and it'll show you an image of a red dot). You'll need to base64 encode the binary data (or url-encode, but base64 is usually preferable for binary data).
Roe,
It took me 2 days and many frustrations just to realize what you meant by storing data in the session state variable. Anyway, below is the solution for anyone to take advantage of.
I, first, put data needed to display in the session state variables
public ActionResult PreviewPage()
{
Session["ImageData"] = contactData.ImageData;
Session["ImageMimeType"] = contactData.ImageMimeType;
return View(contactData);
}
I also created a action method to send data to view. This is where all the magics are done. This action picks up data contained in the Session variables
public FileContentResult GetImage()
{
return File((byte[]Session["ImageData"], (string)Session["ImageMimeType"]);
}
Finally, this how I view accesses to that data without having to fetch needed from a database.
<img src = "<% = Url.Action("GetImage", "Contact")%>" />
It was important that I be able to understand how this works because I'll be doing more of Wizards-like applications in the future.
Thanks very much for helping.

Creating view pages at run time

I'm working on mvc.net and I want to create view pages at run time. Is it possible? If yes then how can I do it?
We actually store NVelocity snippets in a database that we pull together at runtime and marry with ViewData objects to get an output HTML string that we just return via Content() instead of View().
It boils down to something like this (pseudo-code, not actual code):
var _viewDataObject = Products.All();
var _view = PageTemplate.Single(template=>template.Slug == PageTemplateEnums.HomePage);
var _outputHtml = nvelocityMemoryEngine.Transform(_view,_viewDataObject);
return Content(_outputHtml);
While we do some caching for performance reasons, this means you can change views without ever touching Visual Studio or deploying anything at the filesystem level.
It didn't take too much to add things like MimeType handling etc. and we can have people outside of the development team editing the views.

Resources