require_once INSTALLDIR . '/lib/common.php';
require_once INSTALLDIR . '/lib/daemon.php';
require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php';
require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
/**
- * Fetcher for statuses from Twitter
+ * Fetch statuses from Twitter
*
- * Fetches statuses from Twitter and inserts them as notices in local
- * system.
+ * Fetches statuses from Twitter and inserts them as notices
+ *
+ * NOTE: an Avatar path MUST be set in config.php for this
+ * script to work, e.g.:
+ * $config['avatar']['path'] = $config['site']['path'] . '/avatar/';
+ *
+ * @todo @fixme @gar Fix the above. For some reason $_path is always empty when
+ * this script is run, so the default avatar path is always set wrong in
+ * default.php. Therefore it must be set explicitly in config.php. --Z
*
* @category Twitter
* @package StatusNet
* @link http://status.net/
*/
-// NOTE: an Avatar path MUST be set in config.php for this
-// script to work: e.g.: $config['avatar']['path'] = '/statusnet/avatar';
-
class TwitterStatusFetcher extends ParallelizingDaemon
{
/**
$client = new TwitterOAuthClient($token->key, $token->secret);
common_debug($this->name() . ' - Grabbing friends timeline with OAuth.');
} else {
- $client = new TwitterBasicAuthClient($flink);
- common_debug($this->name() . ' - Grabbing friends timeline with basic auth.');
+ common_debug("Skipping friends timeline for $flink->foreign_id since not OAuth.");
}
$timeline = null;
try {
- $timeline = $client->statusesFriendsTimeline();
+ $timeline = $client->statusesHomeTimeline();
} catch (Exception $e) {
common_log(LOG_WARNING, $this->name() .
' - Twitter client unable to get friends timeline for user ' .
return;
}
+ common_debug(LOG_INFO, $this->name() . ' - Retrieved ' . sizeof($timeline) . ' statuses from Twitter.');
+
// Reverse to preserve order
foreach (array_reverse($timeline) as $status) {
continue;
}
- $notice = null;
+ // Don't save it if the user is protected
+ // FIXME: save it but treat it as private
+
+ if ($status->user->protected) {
+ continue;
+ }
- $notice = $this->saveStatus($status, $flink);
+ $notice = $this->saveStatus($status);
if (!empty($notice)) {
- common_broadcast_notice($notice);
+ Inbox::insertNotice($flink->user_id, $notice->id);
}
}
$flink->update();
}
- function saveStatus($status, $flink)
+ function saveStatus($status)
{
- $id = $this->ensureProfile($status->user);
-
- $profile = Profile::staticGet($id);
+ $profile = $this->ensureProfile($status->user);
if (empty($profile)) {
common_log(LOG_ERR, $this->name() .
return null;
}
- // XXX: change of screen name?
-
- $uri = 'http://twitter.com/' . $status->user->screen_name .
- '/status/' . $status->id;
+ $statusUri = $this->makeStatusURI($status->user->screen_name, $status->id);
// check to see if we've already imported the status
- $notice = Notice::staticGet('uri', $uri);
+ $n2s = Notice_to_status::staticGet('status_id', $status->id);
+
+ if (!empty($n2s)) {
+ common_log(
+ LOG_INFO,
+ $this->name() .
+ " - Ignoring duplicate import: {$status->id}"
+ );
+ return Notice::staticGet('id', $n2s->notice_id);
+ }
+
+ common_debug("Saving status {$status->id} with data " . print_r($status, true));
+
+ // If it's a retweet, save it as a repeat!
+
+ if (!empty($status->retweeted_status)) {
+ common_log(LOG_INFO, "Status {$status->id} is a retweet of {$status->retweeted_status->id}.");
+ $original = $this->saveStatus($status->retweeted_status);
+ if (empty($original)) {
+ return null;
+ } else {
+ $author = $original->getProfile();
+ // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
+ // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
+ $content = sprintf(_('RT @%1$s %2$s'),
+ $author->nickname,
+ $original->content);
+
+ if (Notice::contentTooLong($content)) {
+ $contentlimit = Notice::maxContent();
+ $content = mb_substr($content, 0, $contentlimit - 4) . ' ...';
+ }
- if (empty($notice)) {
+ $repeat = Notice::saveNew($profile->id,
+ $content,
+ 'twitter',
+ array('repeat_of' => $original->id,
+ 'uri' => $statusUri,
+ 'is_local' => Notice::GATEWAY));
+ common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}");
+ Notice_to_status::saveNew($repeat->id, $status->id);
+ return $repeat;
+ }
+ }
- // XXX: transaction here?
+ $notice = new Notice();
- $notice = new Notice();
+ $notice->profile_id = $profile->id;
+ $notice->uri = $statusUri;
+ $notice->url = $statusUri;
+ $notice->created = strftime(
+ '%Y-%m-%d %H:%M:%S',
+ strtotime($status->created_at)
+ );
- $notice->profile_id = $id;
- $notice->uri = $uri;
- $notice->created = strftime('%Y-%m-%d %H:%M:%S',
- strtotime($status->created_at));
- $notice->content = common_shorten_links($status->text); // XXX
- $notice->rendered = common_render_content($notice->content, $notice);
- $notice->source = 'twitter';
- $notice->reply_to = null; // XXX: lookup reply
- $notice->is_local = Notice::GATEWAY;
+ $notice->source = 'twitter';
- if (Event::handle('StartNoticeSave', array(&$notice))) {
- $notice->insert();
- Event::handle('EndNoticeSave', array($notice));
+ $notice->reply_to = null;
+
+ if (!empty($status->in_reply_to_status_id)) {
+ common_log(LOG_INFO, "Status {$status->id} is a reply to status {$status->in_reply_to_status_id}");
+ $n2s = Notice_to_status::staticGet('status_id', $status->in_reply_to_status_id);
+ if (empty($n2s)) {
+ common_log(LOG_INFO, "Couldn't find local notice for status {$status->in_reply_to_status_id}");
+ } else {
+ $reply = Notice::staticGet('id', $n2s->notice_id);
+ if (empty($reply)) {
+ common_log(LOG_INFO, "Couldn't find local notice for status {$status->in_reply_to_status_id}");
+ } else {
+ common_log(LOG_INFO, "Found local notice {$reply->id} for status {$status->in_reply_to_status_id}");
+ $notice->reply_to = $reply->id;
+ $notice->conversation = $reply->conversation;
+ }
}
+ }
+ if (empty($notice->conversation)) {
+ $conv = Conversation::create();
+ $notice->conversation = $conv->id;
+ common_log(LOG_INFO, "No known conversation for status {$status->id} so making a new one {$conv->id}.");
}
- Inbox::insertNotice($flink->user_id, $notice->id);
+ $notice->is_local = Notice::GATEWAY;
+
+ $notice->content = common_shorten_links($status->text);
+ $notice->rendered = common_render_content(
+ $notice->content,
+ $notice
+ );
+
+ if (Event::handle('StartNoticeSave', array(&$notice))) {
+
+ $id = $notice->insert();
+ if (!$id) {
+ common_log_db_error($notice, 'INSERT', __FILE__);
+ common_log(LOG_ERR, $this->name() .
+ ' - Problem saving notice.');
+ }
+
+ Event::handle('EndNoticeSave', array($notice));
+ }
+
+ Notice_to_status::saveNew($notice->id, $status->id);
$notice->blowOnInsert();
return $notice;
}
+ /**
+ * Make an URI for a status.
+ *
+ * @param object $status status object
+ *
+ * @return string URI
+ */
+
+ function makeStatusURI($username, $id)
+ {
+ return 'http://twitter.com/'
+ . $username
+ . '/status/'
+ . $id;
+ }
+
/**
* Look up a Profile by profileurl field. Profile::staticGet() was
* not working consistently.
*
- * @param string $url the profile url
+ * @param string $nickname local nickname of the Twitter user
+ * @param string $profileurl the profile url
*
- * @return mixed the first profile with that url, or null
+ * @return mixed value the first Profile with that url, or null
*/
function getProfileByUrl($nickname, $profileurl)
return null;
}
+ /**
+ * Check to see if this Twitter status has already been imported
+ *
+ * @param Profile $profile Twitter user's local profile
+ * @param string $statusUri URI of the status on Twitter
+ *
+ * @return mixed value a matching Notice or null
+ */
+
+ function checkDupe($profile, $statusUri)
+ {
+ $notice = new Notice();
+ $notice->uri = $statusUri;
+ $notice->profile_id = $profile->id;
+ $notice->limit(1);
+
+ if ($notice->find()) {
+ $notice->fetch();
+ return $notice;
+ }
+
+ return null;
+ }
+
function ensureProfile($user)
{
// check to see if there's already a profile for this user
// Check to see if the user's Avatar has changed
$this->checkAvatar($user, $profile);
- return $profile->id;
+ return $profile;
} else {
$this->saveAvatars($user, $id);
- return $id;
+ return $profile;
}
}
$this->updateAvatars($twitter_user, $profile);
}
-
}
function updateAvatars($twitter_user, $profile) {
}
function missingAvatarFile($profile) {
-
foreach (array(24, 48, 73) as $size) {
-
$filename = $profile->getAvatar($size)->filename;
$avatarpath = Avatar::path($filename);
-
if (file_exists($avatarpath) == FALSE) {
return true;
}
}
-
return false;
}