One of the most underrated parts of Dabr IMO is the Twitpic upload page. It allows you to interact with a Twitter helper service that uses the same login information as your twitter account. And since Twitter has speced out how the uploadAndPost process works, lots of other Twitter helper services use it in their API – such as YFrog, Twitgoo, Twitvid, and Posterous (which slickly reverse matches your autopost-twitter information in order to validate your posterous account). But Posterous is pretty slick all around – probably the best tumble blog/micro blog/media blog service out there and certainly the most expandable. Perhaps in the future I might try to integrate some more later.
Anyways, I figure I’d give it a go to add some more services to the twitpic page – keyed off a service dropdown. The hardest part in reality was managing the options allowed by each service (i.e. URL upload instead of file upload, additional message body). In addition, I wanted to add support for a site that I use all the time – Imgur. They didn’t implement the uploadAndPost spec so I had to make a few exceptions as well as add an extra step to post the tweet along with the uploaded image file. Took a while to work out all the kinks (one large kink remaining is that Twitvid uploads don’t work LOL) but this page pretty much saves me from ever having to go to those sites again to upload images!
function twitter_twitpic_page($query) { // Check for oAuth credentials if (user_type() == 'oauth') { return theme('page', 'Error', '<p>You can't do media uploads while accessing Dabr using an OAuth login.</p>'); } //verify that we're entering this page from posting the form if ($_POST['service']) { // format and shrink/truncate associated status message $status = prepare_status($_POST['message'],120); // set the api url based on the service name (all similar except imgur) $postUrl = 'http://'.$_POST['service'].'.com/api/uploadAndPost'; // prepare the fields array with the common elements $postData = array( 'username' => user_current_username(), 'password' => $GLOBALS['user']['password'], 'message' => $status,); // perform service-specific tasks switch ($_POST['service']){ case 'imgur': if (!defined('IMGUR_API_KEY')){ twitter_refresh('twitpic/fail/'.$_POST['service'].'/'.urlencode('API KEY undefined')); } // imgur doesn't use the Twitter standard uploadAndPost spec $postUrl = 'http://imgur.com/api/upload.xml'; //if URL is provided, send URL for imgur to rehost, otherwise use selected file if (empty($_POST['url'])){ $postData = array( 'key' => IMGUR_API_KEY, 'image' => '@'.$_FILES['media']['tmp_name']); } else { $postData = array( 'key' => IMGUR_API_KEY, 'image' => $_POST['url']); } break; case 'yfrog': if (!defined('YFROG_API_KEY')){ twitter_refresh('twitpic/fail/'.$_POST['service'].'/'.urlencode('API KEY undefined')); } $postData['key'] = YFROG_API_KEY; // Yfrog can also accept a URL as the media source if (!empty($_POST['url'])){ $postData['url'] = $_POST['url']; } else { $postData['media'] = '@'.$_FILES['media']['tmp_name']; } break; case 'posterous': // Posterous has an additional comments element and will fall through to the default $postData['body'] = stripslashes($_POST['body']); default: $postData['media'] = '@'.$_FILES['media']['tmp_name']; } // make the api call $response = twitter_process($postUrl,$postData); // check response XML for associated IDs // for uploadAndPost supporting services if (preg_match('#mediaid>(.*)</mediaid#', $response, $matches)) { $id = $matches[1]; // Twitvid allows crossposting to Youtube if (preg_match('#youtube_id>(.*)</youtube_id#', $response, $matches)) { $altid = $matches[1]; } // Posterous sends back a separate shortened URL code if (preg_match('#mediaurl>http://post.ly/(.*)</mediaurl#', $response, $matches)) { $altid = $matches[1]; } // show success messsage and pass IDs to create links to media twitter_refresh("twitpic/confirm/".$_POST['service']."/$id/$altid"); } // response for imgur uses different element names elseif (preg_match('#image_hash>(.*)</image_hash#', $response, $matches)) { $id = $matches[1]; // the secret delete link/code is offered only once and should be shown in the confirmation if (preg_match('#delete_hash>(.*)</delete_hash#', $response, $matches)) { $deleteid = $matches[1]; } // we need the actual imgur link in order to post status to Twitter if (preg_match('#original_image>(.*)</original_image#', $response, $matches)) { $imglinkid = $matches[1]; } // update status with the image link $status .= " $imglinkid "; // post the status to twitter $response = twitter_process('http://twitter.com/statuses/update.json', array('source' => 'dabr', 'status' => $status)); // show success message, link to image, and hidden delete link twitter_refresh("twitpic/confirm/".$_POST['service']."/$id/$deleteid"); } else { // collect errors from response if (preg_match('#error_code>(.*)</error_code#', $response, $matches)) { $error = "Error Code: $matches[1]. "; } if (preg_match('#error_msg>(.*)</error_msg#', $response, $matches)) { $error .= "Error Msg: $matches[1]. "; } if (preg_match('#err.code="(.*)" msg="(.*)" />#', $response, $matches)) { $error = "Error Code: $matches[1] Error Msg: $matches[2]"; } // show failure messages twitter_refresh('twitpic/fail/'.$_POST['service'].'/'.urlencode($error)); } } // Page mode to show confirmation and media links elseif ($query[1] == 'confirm') { $postedlink = "Media: http://$query[2].com/$query[3]"; if ($query[2] == 'imgur' && !empty($query[4])){ $postedlink .= " // Hidden delete link: http://imgur.com/delete/$query[4]"; } if ($query[2] == 'twitvid' && !empty($query[4])){ $postedlink .= " // Youtube: http://www.youtube.com/watch?v=$query[4]"; } if ($query[2] == 'posterous' && !empty($query[4])){ $postedlink = "Post: http://post.ly/$query[4]"; } // show formatted confirmation to add thumbnails $content = "<p>Upload success.</p><p>".twitter_parse_tags($postedlink)."</p>"; } // page mode for failure - show errors elseif ($query[1] == 'fail') { $content = "<p>$query[2] upload failed: $query[3]</p>"; } // otherwise show form else { $content = '<style type="text/css">.disabletrue{background:#ddd;}.disablefalse{background:#fff;}</style> <script type="text/javascript">function disable(sel){service=sel.options[sel.selectedIndex].value;sel.form.url.disabled= (service != 'yfrog' && service != 'imgur');sel.form.body.disabled= (service != 'posterous');sel.form.url.className= 'disable'+(service != 'yfrog' && service != 'imgur');sel.form.body.className= 'disable'+(service != 'posterous');}</script> <form name="twitpic" method="post" action="twitpic" enctype="multipart/form-data"><br />Service: <select name="service" onChange="disable(this);"><option value="twitpic">Twitpic</option><option value="twitgoo">Twitgoo</option><option value="yfrog">Yfrog</option><option value="imgur">Imgur</option><option value="twitvid">Twitvid</option><option value="posterous">Posterous</option></select><br />Upload: <input type="file" name="media" /><br />Message: <input type="text" name="message" maxlength="120" /><br />Image Url: <input type="text" name="url" maxlength="120" /><br />Body:<br><textarea style="position:relative;top:-14px;left:67px;" cols=50 rows=3" name="body"></textarea><br /><input type="submit" value="Upload" /></form> <script type="text/javascript">disable(document.forms['twitpic'].service);</script>'; } return theme('page', 'Twitpic Upload', $content); }
I also had to update the twitter_photo_replace function, which I use to show the thumbnail of the image on the confirm page, to add the imgur regexes
'#imgur.com/([w]{5})[s.ls][.w]*#i' => 'http://imgur.com/%ss.png', '#imgur.com/gallery/([w]+)#i' => 'http://imgur.com/%ss.png', '#imgur.com/delete/([w]+)#i' => 'images/trash.gif',
A lot of code, but to me it’s worth it!
Popularity: unranked [?]




































Of the tens of thousands of messages that are sent through dabr.co.uk daily, only about 200 of them are Twitpic uploads. I’m not keen on encouraging it because modern camera phones are becoming higher resolution and since Dabr is only a website, it can’t shrink those photos for you before you upload.
I do like finding blog posts like this to see different directions people take Dabr though
Comment by David Carrington — January 11, 2010 @ 5:40 am
It really is more an exercise in coding than anything and as i think you mentioned elsewhere, some phones can’t even do file uploads correctly. I guess this was more for my laziness on the desktop version
Comment by webadmin — January 12, 2010 @ 2:32 am