I have used Jsoup library to fetch the metadata from url.
Document doc = Jsoup.connect("http://www.google.com").get();
String keywords = doc.select("meta[name=keywords]").first().attr("content");
System.out.println("Meta keyword : " + keywords);
String description = doc.select("meta[name=description]").get(0).attr("content");
Elements images = doc.select("img[src~=(?i)\\.(png|jpe?g|gif)]");
String src = images.get(0).attr("src");
System.out.println("Meta description : " + description);
System.out.println("Meta image URl : " + src);
But I want to do it in client side using javascript
You can't do it client only because of the cross-origin issue. You need a server side script to get the content of the page.
OR You can use YQL. In this way, the YQL will used as proxy.
https://policies.yahoo.com/us/en/yahoo/terms/product-atos/yql/index.htm
Or you can use https://cors-anywhere.herokuapp.com. In this way, cors-anywhere will used as proxy:
For example:
$('button').click(function() {
$.ajax({
url: 'https://cors-anywhere.herokuapp.com/' + $('input').val()
}).then(function(data) {
var html = $(data);
$('#kw').html(getMetaContent(html, 'description') || 'no keywords found');
$('#des').html(getMetaContent(html, 'keywords') || 'no description found');
$('#img').html(html.find('img').attr('src') || 'no image found');
});
});
function getMetaContent(html, name) {
return html.filter(
(index, tag) => tag && tag.name && tag.name == name).attr('content');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" placeholder="Type URL here" value="http://www.html5rocks.com/en/tutorials/cors/" />
<button>Get Meta Data</button>
<pre>
<div>Meta Keyword: <div id="kw"></div></div>
<div>Description: <div id="des"></div></div>
<div>image: <div id="img"></div></div>
</pre>
Pure Javascript function
From node.js backend (Next.js) I use that:
export const fetchMetadata = async (url) => {
const html = await (await fetch(url, {
timeout: 5000,
headers: {
'User-Agent': 'request'
}
})).text()
var metadata = {};
html.replace(/<meta.+(property|name)="(.*?)".+content="(.*?)".*\/>/igm, (m,p0, p1, p2)=>{ metadata[p1] = decode(p2) } );
return metadata
}
export const decode = (str) => str.replace(/&#(\d+);/g, function(match, dec) {
return String.fromCharCode(dec);
})
You could use it on the client with https://cors-anywhere.herokuapp.com/corsdemo
You can use open-graph-scraper for this, for more info see this answer.
Related
I am making a fake tweet prediction app in which i want to connect my front end with my back end using fast api but I am getting an error 405 i am new to java script as a student and this is my first front end app so please guide me through it
this is the back end
class model_input(BaseModel):
tweet : str
#app.post("/predict")
def predict(input_parameter: model_input):
input_data = input_parameter.json()
dict_parameter = json.loads(input_data)
tweet = dict_parameter["tweet"]
encoded_input = tokenizer.encode_plus(tweet, add_special_tokens=True, return_attention_mask=True)
input_ids, attention_mask = encoded_input["input_ids"], encoded_input["attention_mask"]
input_tensor: Tensor = torch.tensor([input_ids])
attention_tensor = torch.tensor([attention_mask])
model.eval()
with torch.no_grad():
outputs = model(input_tensor, attention_mask=attention_tensor)
logits = outputs[0]
predictions = torch.softmax(logits, dim=1)
y
predicted_class = torch.argmax(predictions).item()
predicted_probability = predictions[0][predicted_class].item()
if predicted_class == 1:
response_text = 0
else:
response_text = 1
response_data = {"prediction": response_text, "probability": predicted_probability}
print(response_data)
return response_data
and this is the front end
<!DOCTYPE html>
<html>
<head>
<title>Text Classification</title>
</head>
<body>
<h1>Text Classification</h1>
<form>
<label for="input-text">Enter text to classify:</label>
<br>
<textarea id="input-text" rows="4" cols="50"></textarea>
<br>
<button id="submit-button">Classify</button>
</form>
<div id="results"></div>
<script>
const inputText = document.getElementById('input-text');
const submitButton = document.getElementById('submit-button');
// Add an event listener to the submit button
submitButton.addEventListener('click', function (event) {
event.preventDefault();
// Get the input text
const text = inputText.value;
// Send the text to the BERT-based model for classification
classifyText(text);
});
function classifyText(text) {
// Send a request to the server with the input text
fetch('http://127.0.0.1:8000/predict', {
method: 'POST',
body: JSON.stringify({ tweet: text }),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
// Get the results element
const results = document.getElementById('results');
// Clear any previous results
results.innerHTML = '';
// Display the results on the web page
if (data.prediction === 1) {
results.innerHTML = 'The text is Real';
}
else if (data.prediction === 0) {
results.innerHTML = 'The text is Fake';
}
else {
results.innerHTML = 'Error: Could not classify the text';
}
})
.catch(error => {
console.error(error);
results.innerHTML = 'Error: ' + error;
});
}
</script>
</body>
</html>
i tried to convert it to get method
Background:
I am try to fill in a pdf file that:
a) has form fields.
b) that is stored on Google Drive.
with data that is stored in Google spreadsheet.
I am using:
Google Apps Script.
HtmlService
PDF-lib.js in a htmlOutput object generated from a htmlTemplate.
The work flow is:
The showModalDialog_downloadFilledPDFform_NAMOFFORM() function is called from a menu.
The function is:
function showModalDialog_downloadFilledPDFform_NAMOFFORM() {
var pdf_template_file_url = getPDFfileURL("form1.pdf");
var htmlTemplate = HtmlService.createTemplateFromFile('downloadFilledPDFformHTML');
htmlTemplate.dataFromServerTemplate = { pdf_template_file: "form1.pdf", pdf_template_file_url: pdf_template_file_url };
var htmlOutput = htmlTemplate.evaluate();
htmlOutput.setWidth(648.1);
htmlOutput.setHeight(286.300)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Download filled PDF');
}
The url that is passed to the htmlTemplate is generated by: "fillPDFForm.gs"
function: fillPDFForm.gs:
var pdfFileNamesAndIDs = [ ]
pdfFileNamesAndIDs.push(["form1.pdf", "1y8F5NgnK50mdtWSR6v1b8pELsbbBJert"])
pdfFileNamesAndIDs.push(["form2.pdf", "1B4BOaI-BqFmhmnFx7FaT-yys-U0vkYKz"])
pdfFileNamesAndIDs.push(["form3.pdf", "17LrJpRA5oBZBqw-2du1H74KxWIX55qYC"])
function getPDFfileURL(fileName) {
var documentID = "";
for (var i in pdfFileNamesAndIDs) {
//console.log(pdfFileNamesAndIDs[i][0]);
if (pdfFileNamesAndIDs[i][0] == fileName) {
documentID = pdfFileNamesAndIDs[i][1];
console.log("documentID: " + documentID);
}
}
var documentFile = DriveApp.getFileById(documentID);
var documentURL = documentFile.getDownloadUrl();
Logger.log("documentURL = "+documentURL);
return documentURL;
}
The Problem:
The URL generated by getPDFfileURL() doesn't work in the html file generated in showModalDialog_downloadFilledPDFform_NAMOFFORM().
The error in Chrome dev console is:
pdf-lib#1.11.0:15 Uncaught (in promise) Error: Failed to parse PDF document (line:0 col:0 offset=0): No PDF header found
at e [as constructor] (pdf-lib#1.11.0:15:189222)
at new e (pdf-lib#1.11.0:15:190065)
at e.parseHeader (pdf-lib#1.11.0:15:401731)
at e.<anonymous> (pdf-lib#1.11.0:15:400782)
at pdf-lib#1.11.0:15:1845
at Object.next (pdf-lib#1.11.0:15:1950)
at pdf-lib#1.11.0:15:887
at new Promise (<anonymous>)
at i (pdf-lib#1.11.0:15:632)
at e.parseDocument (pdf-lib#1.11.0:15:400580)
The basic concept for the html page (shown as a modal dialog box), came from: https://jsfiddle.net/Hopding/0mwfqkv6/3/
The contents of the htmlTemplate are:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<!-- Add Stylesheet -->
<?!= HtmlService.createHtmlOutputFromFile('downloadFilledPDFformCSS').getContent(); ?>
<!-- Add pdf-lib and downloadjs libraries -->
<!-- https://pdf-lib.js.org/ and https://github.com/rndme/download -->
<!-- https://jsfiddle.net/Hopding/0mwfqkv6/3/ -->
<script src="https://unpkg.com/pdf-lib#1.11.0"></script>
<script src="https://unpkg.com/downloadjs#1.4.7"></script>
</head>
<body>
<h2 id="myTitle"></h2>
<p>Click the button to fill form fields in an the following PDF document: <code id="pdf_template_file">pdf-lib</code></p>
<button onclick="fillForm()">Fill PDF</button>
<p class="small">(Your browser will download the resulting file)</p>
</body>
<script>
const data = <?!= JSON.stringify(dataFromServerTemplate) ?>; //Stores the data directly in the javascript code
function removeExtension(filename) {
return filename.substring(0, filename.lastIndexOf('.')) || filename;
}
const pdf_template_file = data.pdf_template_file;
const pdf_template_file_basename = removeExtension(pdf_template_file);
// sample usage
function initialize() {
document.getElementById("myTitle").innerText = pdf_template_file;
//or use jquery: $("#myTitle").text(data.first + " - " + data.last);
document.getElementById("pdf_template_file").innerText = pdf_template_file;
}
// use onload or use jquery to call your initialization after the document loads
window.onload = initialize;
</script>
<script>
const { PDFDocument } = PDFLib;
async function fillForm() {
// Fetch the PDF with form fields
const formUrl = data.pdf_template_file_url
//const formPdfBytes = await fetch(formUrl).then(res => res.arrayBuffer())
const formPdfBytes = await fetch(formUrl, {
redirect: "follow",
mode: 'no-cors',
method: 'GET',
headers: {
'Content-Type': 'application/pdf',
}
}).then(res => res.arrayBuffer());
// Load a PDF with form fields
const pdfDoc = await PDFDocument.load(formPdfBytes);
// Get the form containing all the fields
const form = pdfDoc.getForm()
// Get all fields in the PDF by their names
const invIDField = form.getTextField('invID')
const makeAndModelField = form.getTextField('makeAndModel')
const nameField = form.getTextField('name')
const addressField = form.getTextField('address')
const phoneNumberField = form.getTextField('phoneNumber')
const emailAddressField = form.getTextField('emailAddress')
const dateField = form.getTextField('date')
// Output file name
const INPUT_FNAME = "AN"
const INPUT_LNAME = "Other"
// Fill in the basic info fields
invIDField.setText()
makeAndModelField.setText()
nameField.setText(INPUT_FNAME + " " + INPUT_LNAME)
addressField.setText()
phoneNumberField.setText()
emailAddressField.setText()
dateField.setText()
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save({updateFieldAppearances: false})
const outputPDFfilename = pdf_template_file_basename + "." + INPUT_FNAME + "_" + INPUT_LNAME + ".pdf"
// Trigger the browser to download the PDF document
download(pdfBytes, outputPDFfilename, "application/pdf");
}
</script>
</html>
I have replicated the contents of the html file on my testing webserver. The server has 3 files: index.html, stykesheet.css and form1.pdf
The pdf (on the web server) is the same pdf file that is stored on Google drive.
On my server the following works:
if I use the pdf file that is in the same folder as the html and css files, a filled pdf is offered for download.
...but the following doesn't work:
if I use the same URL that is generated by getPDFfileURL(), nothing happens and no filled pdf is offered for download.
So the question is:
How do I generate the correct URL (for the pdf file stored in Google Drive), so it can then be used by PDF-lib.js (in the htmlTemplate)?
The answer is:
fetch the pdf file from Google drive as raw bytes.
encode the bytes as base64.
pass the base64 string from the GAS function to the htmlTemplate.
This is the function that gets the pdf file and returns it as a base64 encoded string:
function getPDFfileAsBase64() {
var fileId = "";
var url = "https://drive.google.com/uc?id=" + fileId + "&alt=media";
console.log("url: " + url);
var params = {
method: "get",
headers: {
Authorization: "Bearer " + ScriptApp.getOAuthToken(),
},
};
var bytes = UrlFetchApp.fetch(url, params).getContent();
var encoded = Utilities.base64Encode(bytes);
//console.log("encoded: " + encoded);
return encoded;
}
the function to create a modal dialog is:
function showModalDialog_downloadFilledPDFform_form1() {
// Display a modal dialog box with custom HtmlService content.
var pdf_template_file = "form1.pdf";
var pdf_template_file_AsBase64 = getPDFfileAsBase64(pdf_template_file);
var htmlTemplate = HtmlService.createTemplateFromFile('downloadFilledPDFformHTML');
htmlTemplate.dataFromServerTemplate = { pdf_template_file: pdf_template_file, pdf_template_file_AsBase64: pdf_template_file_AsBase64};
var htmlOutput = htmlTemplate.evaluate();
htmlOutput.setWidth(648.1);
htmlOutput.setHeight(286.300)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Download filled PDF');
}
How do I pass a django model to javascript?
Specifically, I want to pass a django Movie model to javascript.
In javascript, I would like to display the id something in the movie model at the time of score with an if statement.
def index(request):
if Movie.objects.order_by('-stars').exists():
movie = list(Movie.objects.order_by('-stars'))
if TV.objects.order_by('-stars').exists():
tv = TV.objects.order_by('-stars')
print(tv)
context = {
'movie':movie,
}
return render(request, 'Movie/index.html',context)
fetchTrendingResults("all", "week")
var mediaType = document.getElementById("media_type")
mediaType.addEventListener("change", function(event) {
fetchTrendingResults(mediaType.options[mediaType.selectedIndex].value, "day")
})
function fetchTrendingResults(media_type, time_window) {
var trendingDiv = document.getElementById("trendings")
trendingDiv.innerHTML = ""
if (media_type == "score"){
var js_list = {{movie}};
}
else{
fetch(`/api/trendings?media_type=${media_type}&time_window=${time_window}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}}
// todo:movieとTVのIDをもらってこれをURLにFethして映画とTVの情報をそれぞれでスターが高い順に表示する。
)
.then(res => res.json())
.then(data => {
for (let i=0; i<data.results.length; i++) {
var mainDiv = document.createElement("div");
mainDiv.setAttribute("class", "card");
mainDiv.setAttribute("style", "width: 18rem;");
var img = document.createElement("img");
img.setAttribute("src", "https://image.tmdb.org/t/p/w200" + data.results[i].poster_path);
img.setAttribute("class", "card-img-top");
img.setAttribute("alt", "...");
var body = document.createElement("div");
body.setAttribute("class", "card-body");
var title = document.createElement("h5");
title.setAttribute("class", "card-title");
if (data.results[i].name) {
title.innerHTML = data.results[i].name;
} else {
title.innerHTML = data.results[i].title;
}
//var text = document.createElement("p");
//text.setAttribute("class", "card-text");
//text.innerHTML = data.results[i].overview;
var link = document.createElement("a");
link.setAttribute("href", "/" + data.results[i].media_type + "/" + data.results[i].id + "/");
link.setAttribute("class", "btn btn-primary");
link.innerHTML = "View Details";
body.appendChild(title);
//body.appendChild(text);
body.appendChild(link);
mainDiv.appendChild(img);
mainDiv.appendChild(body);
document.getElementById("trendings").appendChild(mainDiv);
}
})
}
}
How do I pass a django model to javascript?
Specifically, I want to pass a django Movie model to javascript.
In javascript, I would like to display the id something in the movie model at the time of score with an if statement.
You can send model data by just returning JsonResponse from the view (and for example creating JSON dict by forlooping QuerySet, or using model_to_dict Django built-in method) or by preserving your logic and sending html you need to override - even better - you can do both ways at the same time.
So, basically you write view like this:
from django.forms import model_to_dict
from django.http import Http404
def custom_ajax_view(request):
if request.method != 'POST':
raise Http404
movies = Movie.objects.order_by('-stars')
movie_dict = {}
if movies.exists():
movie_dict = {obj.id: model_to_dict(obj) for obj in movies}
tv = TV.objects.order_by('-stars')
tv_dict = {}
if tv.exists():
tv_dict = {obj.id: model_to_dict(obj) for obj in tv}
context = {
'movie': movie,
}
html = render_to_string(
'Movie/index.html', context=context)
return JsonResponse({
'movies': movie_dict,
'tvs': tv_dict,
'html': html,
})
And then you retrieve data via Ajax method (I prefer using jQuery for that) by writing:
$.ajax({
url: CUSTOM_AJAX_URL,
type: 'post',
dataType: 'json',
success: function (data) {
// Here you retrieve your data and you can do something with it.
console.log(data)
}
});
You also can resolve your CUSTOM_AJAX_URL using template logic (post it at the end of template)
<script>
const CUSTOM_AJAX_URL = "{% url 'custom_ajax_view' %}";
</script>
<script src="{% static 'your_script_name.js' %}"></script>
Then your script should see the CUSTOM_AJAX_URL (if you use script not directly by using inline method, but including script via script tag and placing it with static method in the code). If you place it directly, you can pass URL directly to the AJAX method.
I'm trying to get 3 components to all websites:
Website title
Description
Image/og:image
The way I thought would work was using ajax to fetch the website and then read the meta data, but it doesn't seem to work consistently..
$('#getResults').on('click', (event) => {
let postURL = $('#fetch').val()
$.ajax({
url: 'https://cors-anywhere.herokuapp.com/' + postURL
}).then((data) => {
let html = $(data);
let website_data = {
title: getNameContent(html, 'og:title') || null,
description: getNameContent(html, 'og:description') || null,
image: getNameContent(html, 'og:image') || null,
url: postURL
}
console.log(website_data)
})
})
function getNameContent(html, name) {
return html.filter((index, tag) => tag && tag.name && tag.name == name).attr('content');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
https://www.youtube.com/watch?v=dHHt_VBefeQ //doesn't work<br>
</p>
<input type="text" id="fetch" placeholder="url"/>
<button id="getResults">Search</button>
Some URL's work though, but others don't... Any idea how I can get consistent results? Thank you!
I'm currently implementing a web smartphone application with Phonegap. On this application, users can post images they take with the phone camera on Facebook. This feature has been succesfully implemented only using javascript, by sending a base 64 encoded image. Now, I want to implement the same feature using Twitter.
I found some very interesting blog posts about this and I'm already be able to update the user status only using javascript... but I can't post images too using the update_with_media Twitter web service.
According too this post, someone says it's impossible to implement this operation without using a server side code (like a php script for example).
So my question is : is it possible to use the update_with_media Twitter web service only with javascript ?
I send you my code to have an overview of the current solution. I've taken this article as working base : http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms
Here is my HTML code.
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="../js/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../cordova-2.5.0.js"></script>
<script type="text/javascript" src="../js/childBrowser/childbrowser.js"></script>
<script type="text/javascript" src="../js/helpers/jsOAuth-1.3.6.js"></script>
<script type="text/javascript" src="../js/helpers/twitter.js"></script>
</head>
<body>
<h4>Oodles Twitter App</h4>
<table border="1">
<tr>
<th>Login using Twitter</th>
<th>
<button id="loginBtn" onclick="Twitter.init();">Login</button>
<button id="logoutBtn" onclick="logOut();">Logout</button>
</th>
</tr>
<tr id="tweetText">
<td colspan="2"><textarea id="tweet"></textarea></td>
</tr>
<tr id="tweetBtn">
<td colspan="2" align="right">
<button id="tweeter" onclick="Twitter.tweet();">Tweet</button>
</td>
</tr>
<tr><td colspan="2"><div id="welcome">Please Login to use this app</div></td></tr>
</table>
<br/>
<br/>
<button onclick="javascript:location.reload();">Recharger la page</button>
</body>
</html>
Here is my twitter.js code : (The point is in the post method)
$(document).ready(function() {
document.addEventListener("deviceready", onDeviceReady, false);
});
function onDeviceReady() {
var root = this;
cb = window.plugins.childBrowser;
if (!localStorage.getItem(twitterKey)) {
$("#loginBtn").show();
$("#logoutBtn").hide();
$("tweetBtn").hide();
$("tweetText").hide();
}
else {
$("#loginBtn").hide();
$("#logoutBtn").show();
$("tweetBtn").show();
$("tweetText").show();
}
if (cb != null) {
cb.onLocationChange = function(loc) {
root.locChanged(loc);
};
cb.onClose = function() {
root.onCloseBrowser()
};
cb.onOpenExternal = function() {
root.onOpenExternal();
};
}
}
function onCloseBrowser() {
console.log("onCloseBrowser!");
}
function locChanged(loc) {
console.log("locChanged!");
}
function onOpenExternal() {
console.log("onOpenExternal!");
}
// Consumer key : ...
// Consumer secret : ...
// GLOBAL VARS
var oauth; // It Holds the oAuth data request
var requestParams; // Specific param related to request
var options = {consumerKey: '...', consumerSecret: '...', callbackUrl: "http://www.google.fr"};
var twitterKey = "twtrKey"; // This key is used for storing Information related
var Twitter = {
init: function() {
// Apps storedAccessData , Apps Data in Raw format
var storedAccessData, rawData = localStorage.getItem(twitterKey);
// here we are going to check whether the data about user is already with us.
if (localStorage.getItem(twitterKey) !== null) {
// when App already knows data
storedAccessData = JSON.parse(rawData); //JSON parsing
//options.accessTokenKey = storedAccessData.accessTokenKey; // data will be saved when user first time signin
options.accessTokenSecret = storedAccessData.accessTokenSecret; // data will be saved when user first first signin
// javascript OAuth take care of everything for app we need to provide just the options
oauth = OAuth(options);
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
console.log("USERNAME: " + entry.screen_name);
}
);
}
else {
// we have no data for save user
oauth = OAuth(options);
oauth.get('https://api.twitter.com/oauth/request_token',
function(data) {
requestParams = data.text;
cb.showWebPage('https://api.twitter.com/oauth/authorize?' + data.text); // This opens the Twitter authorization / sign in page
cb.onLocationChange = function(loc) {
Twitter.success(loc);
}; // Here will will track the change in URL of ChildBrowser
},
function(data) {
console.log("ERROR: " + JSON.stringify(data));
}
);
}
},
/*
When ChildBrowser's URL changes we will track it here.
We will also be acknowledged was the request is a successful or unsuccessful
*/
success: function(loc) {
// Here the URL of supplied callback will Load
/*
Here Plugin will check whether the callback Url matches with the given Url
*/
if (loc.indexOf("http://www.google.fr") >= 0) {
// Parse the returned URL
var index, verifier = '';
var params = loc.substr(loc.indexOf('?') + 1);
params = params.split('&');
for (var i = 0; i < params.length; i++) {
var y = params[i].split('=');
if (y[0] === 'oauth_verifier') {
verifier = y[1];
}
}
// Here we are going to change token for request with token for access
/*
Once user has authorised us then we have to change the token for request with token of access
here we will give data to localStorage.
*/
oauth.get('https://api.twitter.com/oauth/access_token?oauth_verifier=' + verifier + '&' + requestParams,
function(data) {
var accessParams = {};
var qvars_tmp = data.text.split('&');
for (var i = 0; i < qvars_tmp.length; i++) {
var y = qvars_tmp[i].split('=');
accessParams[y[0]] = decodeURIComponent(y[1]);
}
$('#oauthStatus').html('<span style="color:green;">Success!</span>');
$('#stage-auth').hide();
$('#stage-data').show();
oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
// Saving token of access in Local_Storage
var accessData = {};
accessData.accessTokenKey = accessParams.oauth_token;
accessData.accessTokenSecret = accessParams.oauth_token_secret;
// Configuring Apps LOCAL_STORAGE
console.log("TWITTER: Storing token key/secret in localStorage");
localStorage.setItem(twitterKey, JSON.stringify(accessData));
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
console.log("TWITTER USER: " + entry.screen_name);
$("#welcome").show();
document.getElementById("welcome").innerHTML = "welcome " + entry.screen_name;
successfulLogin();
// Just for eg.
app.init();
},
function(data) {
console.log("ERROR: " + data);
}
);
// Now we have to close the child browser because everthing goes on track.
window.plugins.childBrowser.close();
},
function(data) {
console.log(data);
}
);
}
else {
// Just Empty
}
},
tweet: function() {
var storedAccessData, rawData = localStorage.getItem(twitterKey);
storedAccessData = JSON.parse(rawData); // Paring Json
options.accessTokenKey = storedAccessData.accessTokenKey; // it will be saved on first signin
options.accessTokenSecret = storedAccessData.accessTokenSecret; // it will be save on first login
// javascript OAuth will care of else for app we need to send only the options
oauth = OAuth(options);
oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
Twitter.post();
}
);
},
/*
We now have the data to tweet
*/
post: function() {
alert('Post !');
var theTweet = $("#tweet").val(); // You can change it with what else you likes.
oauth.post('https://upload.twitter.com/1/statuses/update_with_media.json',
{
'status': theTweet,
'media': //HERE IS THE PROBLEM, WHAT TO DO HERE ?
}, "multipart/form-data",
function(data)
{
alert('Data 1 !');
console.log('------Data1 : ' + data);
var entry = JSON.parse(data.text);
console.log(entry);
done();
},
function(data) {
//var json_result = JSON.parse(data);
//alert(json_result.text.error);
var entry = JSON.stringify(data);
console.log('------Data2 : ' + entry);
}
);
}
}
function done() {
alert("OKKK !");
$("#tweet").val('');
}
function successfulLogin() {
$("#loginBtn").hide();
$("#logoutBtn,#tweet,#tweeter,#tweetBtn,#tweetText").show();
}
function logOut() {
//localStorage.clear();
window.localStorage.removeItem(twitterKey);
document.getElementById("welcome").innerHTML = "Please Login to use this app";
$("#loginBtn").show();
$("#logoutBtn,#tweet,#tweeter,#tweetText,#tweetBtn").hide();
}
After many tests (sending a base64 image, sending a blob, sending a binary file, ...) here is the return message from Twitter I have :
{\"errors\":[{\"message\":\"Internal
error\",\"code\":131}]}","xml":"","requestHeaders":{"Content-Type":"multipart/form-data"},"responseHeaders":{"date":"Fri,
19 Apr 2013 15:45:28
GMT","content-encoding":"deflate","strict-transport-security":"max-age=631138519","status":"500
Internal Server
Error","server":"tfe","content-type":"application/json;
charset=utf-8","version":"HTTP/1.1"}}
A "solution" (by send a blob) have been posted on the Twitter dev forum but not working for me : dev.twitter.com/discussions/6969
Does anyone want to implement the same feature or have a solution ? Thank you !
------ EDITED :
I just want to use Javascript and I don't want to implement any server-side solution (no PHP, C#, Java...).
According to the docs, Twitter requires the multipart/form-data enctype, which means a base64 string isn't going to work.
Unlike POST statuses/update, this method expects raw multipart data. Your POST request's Content-Type should be set to multipart/form-data with the media[] parameter ~ https://dev.twitter.com/docs/api/1/post/statuses/update_with_media
However, you could host an endpoint that takes base64, converts it to a real file, and forwards the request to Twitter. For example (untested):
<?php
$base64 = $_POST['image'];
$data = base64_decode( $base64 );
// Make name unique to avoid conflicts.
$temp_file = uniqid() . $_POST['name'];
// Save the file to a temp location.
file_put_contents( $temp_file, $data );
$temp_info = pathinfo( $temp_file );
$temp_type = $temp_info['extension'];
$temp_name = basename( $temp_file, '.' . $temp_type );
// OAuth library recommended by Twitter: https://github.com/themattharris/tmhOAuth
// See original: https://github.com/themattharris/tmhOAuth-examples/blob/master/images.php
require 'tmhOAuth.php';
require 'tmhUtilities.php';
$tmhOAuth = new tmhOAuth( array(
'consumer_key' => $_POST['consumer_key'],
'consumer_secret' => $_POST['consumer_secret'],
'user_token' => $_POST['user_token'],
'user_secret' => $_POST['user_secret'],
));
// note the type and filename are set here as well
// Edit: Not sure if the `type` and `filename` params are necessary.
$params = array( 'media[]' => "#{$temp_file};type={$temp_type};filename={$temp_name}" );
$code = $tmhOAuth->request( 'POST', $tmhOAuth->url( '1/status/update_with_media' ),
$params,
true, // use auth
true // multipart
);
// Remove temp file.
unlink( $temp_file );
if ( $code == 200 ) {
tmhUtilities::pr( json_decode( $tmhOAuth->response['response'] ) );
}
tmhUtilities::pr( htmlentities( $tmhOAuth->response['response'] ) );
?>
And you might call it like:
$.ajax({
// You'll want to use https to protect the oauth info.
url: "https://mysite.com/proxy.php",
type: "POST",
data: {
image: "base64 data...",
name: "foo.png",
consumer_key: options.consumerKey,
consumer_secret: options.consumerSecret,
user_token: options.accessTokenKey,
user_secret: options.accessTokenSecret
},
success: function( data ) {
console.log( data );
}
});
For anyone trying to post images to Twitter using client JS, I was able to post to twitter using the solution by gary-buynary-co-za (https://github.com/bytespider/jsOAuth/pull/11) at the end of this forum. Pretty much ended up using Phonegap FileTransfer and FileTransferOptions objects for transferring image to twitter api, but used jsOAuth for preparing FileTransferOptions headers and signatures. The solution could definitely be cleaned up though.