I am using the rotten tomatoes API, which is fairly straight forward. The following is my basic code:
var apikey = "xxxxx";
function queryForMovie(query) {
queryUrl = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=" + apikey + "&q=" + encodeURI(query);
$.ajax({
url: queryUrl,
dataType: "jsonp",
success: queryCallback
});
}
function queryCallback(data) {
var el = $('#movie-listings');
$.each(data.movies, function(index, movie) {
el.append('img src="' + movie.posters.original + '" alt="' + movie.title + '"');
})
};
$(document).on("load", queryForMovie("Star Wars"));
However, this gives back a very small image.
What would be a good way to get a larger sized image, while limiting requests where possible?
** UPDATE **
Rotten Tomatoes has made configuration changes such that trying to reference cloudfront urls directly no longer works. Therefor, this solution no longer works.
Such is the danger of using non-sanctioned workarounds.
Does anybody know of a good service for getting movie posters?
Original non-working answer:
Even though the Rotten Tomatoes API lists four separate images in a movies poster object (thumbnail,profile,detailed, and original), they are all, currently, identical URLs:
"posters": {
"thumbnail": "http://resizing.flixster.com/AhKHxRwazY3brMINzfbnx-A8T9c=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg",
"profile": "http://resizing.flixster.com/AhKHxRwazY3brMINzfbnx-A8T9c=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg",
"detailed": "http://resizing.flixster.com/AhKHxRwazY3brMINzfbnx-A8T9c=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg",
"original": "http://resizing.flixster.com/AhKHxRwazY3brMINzfbnx-A8T9c=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg"
}
According to RT, high-resolution poster images are no longer available via the APIs to maintain focus on ratings and reviews, more detailed content.
However, if you're willing to "order off menu," you can still get at the full resolution image. The part of the poster image urls following /54x80/ is the cloudfront url for the original image:
http://resizing.flixster.com/AhKHxRwazY3brMINzfbnx-A8T9c=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg
...becomes...
http://dkpu1ddg7pbsk.cloudfront.net/movie/11/13/43/11134356_ori.jpg
A javascript implementation might look something like this:
// movie = RT API movie object
var original = movie.posters.original.replace(/^.*?\/[\d]+x[\d]+\//,"http://");
This image will ordinarily be much much larger than 54x80, and it may not be feasible to load and display large lists of these images. Trying to modify the url resizing.flixster.com url doesn't work--there appears to be some kind of resource dependent hash involved. If you want to be able to downscale the images, you need to set up or find an image proxy service. I found that Pete Warden's article on resizing and caching images with cloudfront to be of great help.
An example using the service he set up in the article might look like http://imageproxy.herokuapp.com/convert/resize/200x285/source/http%3A%2F%2Fdkpu1ddg7pbsk.cloudfront.net%2Fmovie%2F11%2F13%2F43%2F11134356_ori.jpg
In javascript, this would look something like:
// Match url: http://[some.kind/of/url/[height]x[width]/[original.cloudfront/url]
var url_parts = movie.posters.original.match(/^.*?\/([\d]+)x([\d]+)\/(.*)/);
var ratio = url_parts[1] / url_parts[2], // Determine the original image aspect ratio from the resize url
size = 200, // This is the final width of image (height is determined with the ratio)
original = "http://" + url_parts[3],
wxh = [size, Math.round(size/ratio)].join("x");
// Construct the final image url
movie.posters.original = [
"http://imageproxy.herokuapp.com/convert/resize/",
wxh,
"/source/",
encodeURIComponent(original)
].join("");
// The first request of this URL will take some time, as the original image will likely need to be scaled to the new size. Subsequent requests (from any browser) should be much quicker, so long as the image remains cached.
NOTE: Doing something like this depends on Rotten Tomatoes keeping their resize urls the same form (resize url + [width]x[height] + encoded cloudfront url). Unless you set up your own image proxy service, you are also at the mercy of the proxy owner, as far as uptime, performance, security, and image quality is concerned.
Related
I am using Google Apps Script to create a page, on which I would like to embed maps. The maps themselves would be static, but the map could be different depending on other parameters (it’s a genealogy page, and I’d like to display a map of birth and death locations, and maybe some other map points, based on a selected individual).
Using Google’s Maps service, I know that I can create a map, with a couple points built in.
Function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600,400)
.addMarker('Chicago, Illinois') // markers would be based on a passed parm; this is just test data
.addMarker('Pocatello, Idaho');
// *** This is where I am looking for some guidance
return(); // obviously, I'm not returning a blank for real
}
Within the map class, there are a number of things I can do with it at this point.
I could create a URL, and pass that back. That appears to require an API account, which at this point, I do not have (and ideally, would like to avoid, but maybe I’ll have to do that). It also appears that I will run into CORB issues with that, which I think is beyond my knowledge (so if that’s the solution, I’ll be back for more guidance).
I could create a blob as an image, and pass that back to my page. I have tried this using a few different examples I have found while researching this.
Server Side
function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600,400)
.addMarker('Chicago, Illinois')
.addMarker('Pocatello, Idaho');
var mapImage = map.getAs("image/png");
// OR
// var mapImage = map.getBlob();
return(mapImage);
}
Page side
<div id=”mapDiv”></div>
<script>
$(function() {
google.script.run.withSuccessHandler(displayMap).getMapImage();
}
function displayMap(mapImage) {
var binaryData = [];
binaryData.push(mapImage);
var mapURL = window.URL.createObjectURL(new Blob(binaryData, {type: "image/png"}))
var mapIMG = "<img src=\'" + mapURL + "\'>"
$('#mapDiv').html(mapIMG);
}
</script>
The page calls getMapImage() on the server, and the return data is sent as a parm to displayMap().
var mapIMG ends up resolving to <img src='blob:https://n-a4slffdg23u3pai7jxk7xfeg4t7dfweecjbruoa-0lu-script.googleusercontent.com/51b3d383-0eef-41c1-9a50-3397cbe83e0d'> This version doesn't create any errors in the console, which other options I tried did. But on the page, I'm just getting the standard 16x16 image not found icon.
I’ve tried a few other things based on what I’ve come across in researching this, but don’t want to litter this post with all sorts of different code snippets. I’ve tried a lot of things, but clearly not the right thing yet.
What’s the best / correct (dare I ask, simplest) way to build a map with Google’s Map class, and then serve it to a web page?
EDIT: I added a little more detail on how the server and page interact, in response to Tanaike's question.
Modification points:
I think that in your script, Blob is returned from Google Apps Script to Javascript using google.script.run. Unfortunately, in the current stage, Blob data cannot be directly sent from from Google Apps Script to Javascript. I think that this might be the reason of your issue.
In this case, I would like to propose to directly create the data URL at the Google Apps Script side. When your script is modified, it becomes as follows.
Modified script:
Google Apps Script side:
function getMapImage() {
var map = Maps.newStaticMap()
.setSize(600, 400)
.addMarker('Chicago, Illinois')
.addMarker('Pocatello, Idaho');
var blob = map.getAs("image/png"); // or map.getBlob()
var dataUrl = `data:image/png;base64,${Utilities.base64Encode(blob.getBytes())}`;
return dataUrl;
}
Javascript side:
$(function() {
google.script.run.withSuccessHandler(displayMap).getMapImage();
});
function displayMap(mapURL) {
var mapIMG = "<img src=\'" + mapURL + "\'>"
$('#mapDiv').html(mapIMG);
}
In your Javascript side, $(function() {google.script.run.withSuccessHandler(displayMap).getMapImage();} is not enclosed by ). Please be careful this.
Note:
In my environment, when I saw <div id=”mapDiv”></div>, this double quote ” couldn't be used. So if in your environment, an error occurs by <div id=”mapDiv”></div>, please modify ” to " like <div id="mapDiv"></div>.
Reference:
base64Encode(data)
Is it possible to update the CSS image pointed by the passed-in url in "backgound-image: \"<some-url>\" in Javascript only when the source image is changed in the server. I.e. cache the image, and then retrieve the image from the server when it's needed to be reload and compare it with the cached image. Then, reload it when it's updated only. I know that in order to refresh an image in CSS through Javascript, the image must have a different string after the "?" in the image source, and one way to do so is by using the current time returned by Date.getTime method after "?". E.g. (I got this method from here https://stackoverflow.com/a/1077051/7000599):
$(".some-css-class").css("backgound-image", "url(" + "\"" + some_source + "?" + new Date().getTime() + "\"" + ")");
However, I would like to call the above logic when I need to update the background-image only when it detect the image has been changed. So is there a way to detect such changes?
Give each image a unique id and then poll the server every so often to see if there's a new id, and if so, change the underlying image.
You may add API to server side which returns some hash value for image content. So when you put the image for first time - add hash-value for specific image after '?'.
$(".come-css-class").css("backgound-image", "url(" + "\"" + some_source + "?" + imageHash + "\"" + ")");
Than from time to time call the hash API and replace background-image property. When image will be updated on server - it will return new hash-value - so css will reload the image.
To automatically update the image through JavaScript itself (without relying on any back-end script), you would need to poll the server periodically to check whether the modification date was greater than a cached copy of the image. You would then need to refresh the page if this was the case.
This would be done similar to the following:
var previous = null;
var current = null;
var image_url = 'IMAGE URL';
setInterval(function() {
var req = new XMLHttpRequest(); // Poll the server
req.open("HEAD", image_url, false);
req.send(null);
if (req.status == 200) {
current = req.getResponseHeader('Last-Modified'); // Get modification time
}
if (previous && current && previous !== current) { // If it's been modified
location.reload(); // Refresh
}
previous = current; // Store the 'new' image information
$(".come-css-class").css("background-image", "url(" + "\"" + image_url + "\""); // Update the image
}, 2000); // Repeat every two seconds
Also note that you called it backgound-image in your question. You need to ensure that you call it background-image in order to function correctly.
Hope this helps! :)
Similar to a reply comment to #Nosyara, I think the better approach to this problem I have found so far is by using the HTTP header ETag to detect whether the source image (or file as well) is changed from the last cached file. I think #ObsidianAge's answer would also work (i.e. using the Last-Modified header), but for some reason it doesn't show any changes when the source image (or file) is changed. I did a simple local Apache server and simple webpage with a Javascript onInterval event to console.log whether the file has changed or not, but it doesn't seem the case. So apparently ETag is a way to do it. Here's the Wikipedia page explaining it's purposes (it has other purposes too): https://en.wikipedia.org/wiki/HTTP_ETag.
I'm trying to grab the highest quality image for each item that a GetSellerList request returns. The HQ images can be viewed manually by clicking the image on a product page (so I know they exist).
Unfortunately, it only returns medium sized images. I've googled and googled, only to find a lot of mentions of SelectorOutput, which can only be used in the Finding API and that is completely irrelevant to what I'm trying to do.
Here's my xml input (note that my auth is taken care of with a js library I'm using):
var xml = '<?xml version="1.0" encoding="UTF-8"?>' +
'<GetSellerListRequest xmlns="urn:ebay:apis:eBLBaseComponents">' +
'<RequesterCredentials>' +
'<eBayAuthToken> <!-- my ebayAuthToken -->' +
'</RequesterCredentials>' +
'<UserID>samurai-gardens</UserID>' +
'<StartTimeFrom>2016-01-01T23:35:27.000Z</StartTimeFrom>' +
'<StartTimeTo>2016-02-01T23:35:27.000Z</StartTimeTo>' +
'<DetailLevel>ItemReturnDescription</DetailLevel>' +
'<Pagination ComplexType="PaginationType">' +
'<EntriesPerPage>10</EntriesPerPage>' +
'<PageNumber>1</PageNumber>' +
'</Pagination>' +
'</GetSellerListRequest>"';
I am getting the correct output, I just don't see how I can pull the large images with this. Thanks ebay for a super frustrating api!
Just to clarify the comments posted on this question:
To obtain a high resolution image associated with a product listing perform the following..
Utilize a GetSellerRequest as formatted below to obtain the picture URL from the Item Details:
var xml = '<?xml version="1.0" encoding="UTF-8"?>' +
'<GetSellerListRequest xmlns="urn:ebay:apis:eBLBaseComponents">' +
'<RequesterCredentials>' +
'<eBayAuthToken> <!-- my ebayAuthToken -->' +
'</RequesterCredentials>' +
'<UserID>samurai-gardens</UserID>' +
'<StartTimeFrom>2016-01-01T23:35:27.000Z</StartTimeFrom>' +
'<StartTimeTo>2016-02-01T23:35:27.000Z</StartTimeTo>' +
'<DetailLevel>ItemReturnDescription</DetailLevel>' +
'<Pagination ComplexType="PaginationType">' +
'<EntriesPerPage>10</EntriesPerPage>' +
'<PageNumber>1</PageNumber>' +
'</Pagination>' +
'</GetSellerListRequest>"';
This should product a URL such as the following:
i.ebayimg.com/00/s/ODAwWDYyOQ==/z/3eEAAOSwSdZWdJRL/$_1.JPG?set_id=880000500F
Once this URL is obtained, it needs to be modified to point to the high resolution image option. Through trial and error this appears to be either .JPG images 3 or 57 (and possibly others). Each image has different alignments which is the cause of the multiple 'high resolution' options. Modify the returned URL using standard string manipulation techniques to obtain the following:
i.ebayimg.com/00/s/ODAwWDYyOQ==/z/3eEAAOSwSdZWdJRL/$_3.JPG
This could be obtained as follows (in c#). The snippet below was not tested. Make sure there isn't an off by one bug in the substring. There are a myriad way of doing this, this just happens to be what I thought of..
string url = "i.ebayimg.com/00/s/ODAwWDYyOQ==/z/3eEAAOSwSdZWdJRL/$_1.JPG?set_id=880000500F";
int index = url.LastIndexOf(Convert.ToChar(#"/");
url = url.Substring(0,index+1);
url = url + #"/$_3.JPG";
If you are using c# (which I realize the original post was for javascript) you can use information in the following thread to obtain an image stream from the URL: URL to Stream
Here is a post for displaying an image from URL using Javascript: URL To Display Javascript
UPDATE: The original question was about how to get a square thumbnail, which apparently is not possible. I have changed the question to be how do I get a custom sized thumbnail. The aspect ratio can be left as-is.
I can piece together a solution from Using facebook graph api how to get news feed with large picture size if the feed type is photo? but I am hoping for something better.
I can get a list of image sizes using
https://graph.facebook.com/v2.0/{object_id}?access_token={token}
and then I could rummage through that list to find one that is large enough but not too large and make a second request for that image.
Or, following the answers in Facebook Graph API : get larger pictures in one request, I could get a full size image returned directly in the post feed request with
https://graph.facebook.com/v2.2/{object_id}/posts?fields=full_picture
But I don't need a full size image. Is there not a way to do something like in the second example but for arbitrary image dimensions, or at least for one of the presets like you get from the first example?
Original question:
I use the Javascript below to dump a custom styled facebook feed onto a website. It shows the date and the posted text and if there is an image it grabs that as well. It looks like Facebook defaults the image to 130px wide and maintains the aspect ratio of the original image. But Facebook has a way of generating square versions of images right?
I see /s130x130/in the image URL but unfortunately changing that results in nothing being returned, because it looks like there are some random IDs in the query string that only FB knows about. I saw an example of different sized square thumbnails somewhere, but those random IDs changed for each size. So is there a way to retrieve the square versions of my images within my Javascript or if not, is there any way at all to do it?
$(function() {
$.getJSON("https://graph.facebook.com/v2.2/1551867661729482/feed?access_token=XXXXXXXX", function(data) {
var maxPosts = 3
$.each(data.data, function(x) {
if (maxPosts > 0) {
if (data.data[x].from.name == "D'Arts") {
var message = data.data[x].message || //normal post
data.data[x].story.replace(/^You /, '').capitalizeFirstLetter() || //other updates without user text
"";
var pic = data.data[x].picture;
pic = pic ? '<img class="fb-thumb" src="' + pic + '"></img>' : '';
var date = new Date( data.data[x].created_time ).toString().replace(/.* (\w\w\w \d\d) .*/,"$1");
var link = data.data[x].link;
$('#Facebook .feed-goes-here').append('<h3>'+date+'</h3>' + pic + '<p>' + message + '</p>');
maxPosts--;
}
} else {
return false
}
})
})
})
I am trying to capture a still frame from an (any) external swf file, by using my own flash movie as a proxy to load it and hand information regarding the Stage onto javascript. I want to keep it as wide compatible as possible, so I went with AS2 / Flash 8 for now.
The script works fine in the Flash debugger, i.e. the
trace(flash2canvasScreenshot.getPixel(w, h).toString(16));
returns the correct pixel color, where as:
ExternalInterface.call("sendToJS",flash2canvasScreenshot.getPixel(w, h).toString(16));
in the published movie doesn't.
This method can obviously be quite slow for large flash (dimension wise) movies, as it iterates every single pixel. If someone has any better methods in mind, feel free to share, but as said, the problem I am facing is that I am getting differentiating results in debugging and publishing, with the pixel information not getting fetched when published.
import flash.display.BitmapData;
import flash.external.*;
var myLoader:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadInit = function(target_mc:MovieClip)
{
var stageW = Stage.width;
var flash2canvasScreenshot:BitmapData = new BitmapData(stageW, Stage.height, false, 0x00000000);
var pixels:Array = new Array();
flash2canvasScreenshot.draw(element);
for (w = 0; w <= stageW; w++)
{
trace(flash2canvasScreenshot.getPixel(w, h).toString(16)); // this gives correct color value for the pixels in the debugger
ExternalInterface.call("sendToJS",flash2canvasScreenshot.getPixel(w, h).toString(16)); // this just returns the bitmap default color, 0 in this case.
/*
for (h = 0; h <= Stage.height; h++)
{
var pixel = flash2canvasScreenshot.getPixel(w, h).toString(16);
pixels.push(pixel);
}
*/
}
//ExternalInterface.call("sendToJS",pixels.toString());*/
};
myLoader.addListener(mclListener);
myLoader.loadClip("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf", 0);
//myLoader.loadClip("https://s.ytimg.com/yt/swfbin/watch_as3-vflJjAza6.swf", 0);
//myLoader.loadClip(_level0.flash2canvasurl, _root.mc);
There are few problems with the snippet you posted:
like the one Joey mentioned, but the one that stands out from my
point of view is the element variable which isn't defined
anywhere, so that either is a type o, or you're trying to draw an
undefined object.
You're drawing as soon as the load is finished, but the animation you're loading might start slightly later. Maybe take the snapshot a bit after the load is complete.
Haven't touched as2 for some time and don't remember how security issue are handled, but if you're swf is loading another swf from a different domain, then the domain hosting the swf you're loading should also have a crossdomain.xml policy file allowing you to access the content of the loaded swf. If you simply load and display a swf from another domain, that's fine. However, if you're trying to draw the swf using BitmapData, you're actually attempting to access pixel data from the content of that swf, therefore you would need permissions. If you have no control over the crossdomain policy file, you might need to use a server side script to copy/proxy the file over to a domain that can grant your loaded swf access.
Here's a simplified version of your snippet that works (sans the external interface/pixel values part):
var myLoader:MovieClipLoader = new MovieClipLoader();
var mclListener:Object = new Object();
mclListener.onLoadInit = function(target_mc:MovieClip)
{
var pixels:Array = new Array();
setTimeout(takeSnapshot,2000,target_mc);
}
myLoader.addListener(mclListener);
myLoader.loadClip("http://www.bbc.co.uk/science/humanbody/sleep/sheep/reaction_version5.swf",1);
//myLoader.loadClip("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf", 1);
//myLoader.loadClip("https://s.ytimg.com/yt/swfbin/watch_as3-vflJjAza6.swf", 0);
function takeSnapshot(target:MovieClip):Void {
var flash2canvasScreenshot:BitmapData = new BitmapData(150, 150, false, 0x00000000);//tiny sample
flash2canvasScreenshot.draw(target);
_level1._alpha = 20;//fade the loaded content
_level0.attachBitmap(flash2canvasScreenshot,0);//show the snapshop. sorry about using _root
}
Here's a quick zoomed preview of the 150x150 snap:
Here's an as3 snippet to illustrate the security sandbox handling issue:
var swf:Loader = new Loader();
swf.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderComplete);
swf.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,loaderSecurityError);
swf.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,loaderIOError);
swf.load(new URLRequest("http://i.cdn.turner.com/cnn/cnnintl_adspaces/2.0/creatives/2010/6/9/21017300x250-03.swf"),new LoaderContext(true));
function loaderComplete(event:Event):void{
setTimeout(takeSWFSnapshot,2000);
}
function loaderSecurityError(event:SecurityErrorEvent):void {
trace('caught security error',event.errorID,event.text);
}
function loaderIOError(event:IOErrorEvent):void{
trace('caught I/O error',event.errorID,event.text,'\tattempting to load\t',swf.contentLoaderInfo.url);
}
function takeSWFSnapshot():void{
var clone:BitmapData = new BitmapData(swf.content.width,swf.content.height,false,0);
try{
clone.draw(swf.content);
}catch(e:SecurityError){
trace(e.name,e.message,e.getStackTrace());
}
addChild(new Bitmap(clone));
}
HTH
My approach to this would be:
-Use AS3 for the reason lukevanin commented:
Just remember that AS3 can load an AS2 SWF, but an AS2 SWF cannot load
an AS3 SWF, so you actually achieve greater compatibility (with your
content) if you publish AS3
-Use a proxy file to fetch the swf file to get around sandbox violation issues (although if the swf loads external resources and uses relative paths it might get a bit more complex)
-Take a snapshot of the frame ( see George Profenza's solution )
-Encode the image using base64 and send that** to a JS method, and then decode to get the image.
** I'm pretty sure there are no size limitations...