<?php
/**
* Name: Twitter Connector
- * Description: Relay public postings to a connected Twitter account
+ * Description: Bidirectional (posting, relaying and reading) connector for Twitter.
* Version: 1.0.4
* Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
* Requirements: PHP5, curl [Slinky library]
*/
+require_once('include/enotify.php');
+require_once("include/socgraph.php");
+
define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
function twitter_install() {
register_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
register_hook('expire', 'addon/twitter/twitter.php', 'twitter_expire');
register_hook('prepare_body', 'addon/twitter/twitter.php', 'twitter_prepare_body');
+ register_hook('check_item_notification','addon/twitter/twitter.php', 'twitter_check_item_notification');
logger("installed twitter");
}
unregister_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
unregister_hook('expire', 'addon/twitter/twitter.php', 'twitter_expire');
unregister_hook('prepare_body', 'addon/twitter/twitter.php', 'twitter_prepare_body');
+ unregister_hook('check_item_notification','addon/twitter/twitter.php', 'twitter_check_item_notification');
// old setting - remove only
unregister_hook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
}
+function twitter_check_item_notification($a, &$notification_data) {
+ $own_id = get_pconfig($notification_data["uid"], 'twitter', 'own_id');
+
+ $own_user = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
+ intval($notification_data["uid"]),
+ dbesc("twitter::".$own_id)
+ );
+
+ if ($own_user)
+ $notification_data["profiles"][] = $own_user[0]["url"];
+}
+
function twitter_follow($a, &$contact) {
logger("twitter_follow: Check if contact is twitter contact. ".$contact["url"], LOGGER_DEBUG);
switch ($action) {
case "delete":
- $result = $cb->statuses_destroy($post);
+ // To-Do: $result = $cb->statuses_destroy($post);
break;
case "like":
$result = $cb->favorites_create($post);
$image = "";
- if (isset($msgarr["url"]))
+ if (isset($msgarr["url"]) AND ($msgarr["type"] != "photo"))
$msg .= "\n".$msgarr["url"];
elseif (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
$image = $msgarr["image"];
unlink($tempfile);
logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
+
+ if ($result->source)
+ set_config("twitter", "application_name", strip_tags($result->source));
+
if ($result->errors OR $result->error) {
logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
$result = $tweet->post($url, $post);
logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
+
+ if ($result->source)
+ set_config("twitter", "application_name", strip_tags($result->source));
+
if ($result->errors) {
logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
$applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
set_config('twitter','consumerkey',$consumerkey);
set_config('twitter','consumersecret',$consumersecret);
- set_config('twitter','application_name',$applicationname);
+ //set_config('twitter','application_name',$applicationname);
info( t('Settings updated.'). EOL );
}
function twitter_plugin_admin(&$a, &$o){
// name, label, value, help, [extra values]
'$consumerkey' => array('consumerkey', t('Consumer key'), get_config('twitter', 'consumerkey' ), ''),
'$consumersecret' => array('consumersecret', t('Consumer secret'), get_config('twitter', 'consumersecret' ), ''),
- '$applicationname' => array('applicationname', t('Name of the Twitter Application'), get_config('twitter','application_name'),t('set this to avoid mirroring postings from ~friendica back to ~friendica'))
+ //'$applicationname' => array('applicationname', t('Name of the Twitter Application'), get_config('twitter','application_name'),t('Set this to the exact name you gave the app on twitter.com/apps to avoid mirroring postings from ~friendica back to ~friendica'))
));
}
}
}
+ $abandon_days = intval(get_config('system','account_abandon_days'));
+ if ($abandon_days < 1)
+ $abandon_days = 0;
+
+ $abandon_limit = date("Y-m-d H:i:s", time() - $abandon_days * 86400);
$r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
if(count($r)) {
foreach($r as $rr) {
+ if ($abandon_days != 0) {
+ $user = q("SELECT `login_date` FROM `user` WHERE uid=%d AND `login_date` >= '%s'", $rr['uid'], $abandon_limit);
+ if (!count($user)) {
+ logger('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
+ continue;
+ }
+ }
+
logger('twitter: importing timeline from user '.$rr['uid']);
twitter_fetchhometimeline($a, $rr["uid"]);
$msgarr = plaintext($a, $item, $max_char, true, 8);
$msg = $msgarr["text"];
- if (isset($msgarr["url"]))
+ if (isset($msgarr["url"]) AND ($msgarr["type"] != "photo"))
$msg .= " ".$msgarr["url"];
if (isset($msgarr["image"]))
require_once('mod/item.php');
require_once('include/items.php');
+ require_once('mod/share.php');
require_once('library/twitteroauth.php');
$connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
if (count($posts)) {
foreach ($posts as $post) {
- if ($post->id_str > $lastid)
+ if ($post->id_str > $lastid) {
$lastid = $post->id_str;
+ set_pconfig($uid, 'twitter', 'lastid', $lastid);
+ }
if ($first_time)
continue;
- if (!strpos($post->source, $application_name)) {
+ if (!stristr($post->source, $application_name)) {
$_SESSION["authenticated"] = true;
$_SESSION["uid"] = $uid;
$converted = twitter_expand_entities($a, $_REQUEST['body'], $post->retweeted_status, true, $picture);
$_REQUEST['body'] = $converted["body"];
- $_REQUEST['body'] = "[share author='".$post->retweeted_status->user->name.
- "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
- "' avatar='".$post->retweeted_status->user->profile_image_url_https.
- "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
- $_REQUEST['body'];
+ if (function_exists("share_header"))
+ $_REQUEST['body'] = share_header($post->retweeted_status->user->name, "https://twitter.com/".$post->retweeted_status->user->screen_name,
+ $post->retweeted_status->user->profile_image_url_https, "",
+ datetime_convert('UTC','UTC',$post->retweeted_status->created_at),
+ "https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str).
+ $_REQUEST['body'];
+ else
+ $_REQUEST['body'] = "[share author='".$post->retweeted_status->user->name.
+ "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
+ "' avatar='".$post->retweeted_status->user->profile_image_url_https.
+ "' posted='".datetime_convert('UTC','UTC',$post->retweeted_status->created_at).
+ "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
+ $_REQUEST['body'];
+
$_REQUEST['body'] .= "[/share]";
} else {
$_REQUEST["body"] = $post->text;
}
}
-function twitter_fetch_contact($uid, $contact, $create_user) {
+function twitter_fix_avatar($avatar) {
require_once("include/Photo.php");
- if ($contact->id_str == "")
- return(-1);
-
- $avatar = str_replace("_normal.", ".", $contact->profile_image_url_https);
+ $new_avatar = str_replace("_normal.", ".", $avatar);
- $info = get_photo_info($avatar);
+ $info = get_photo_info($new_avatar);
if (!$info)
- $avatar = $contact->profile_image_url_https;
+ $new_avatar = $avatar;
- // Check if the unique contact is existing
- // To-Do: only update once a while
- $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
- dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
+ return $new_avatar;
+}
- if (count($r) == 0)
- q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
- dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
- dbesc($contact->name),
- dbesc($contact->screen_name),
- dbesc($avatar));
- else
- q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
- dbesc($contact->name),
- dbesc($contact->screen_name),
- dbesc($avatar),
- dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
+function twitter_fetch_contact($uid, $contact, $create_user) {
+
+ if ($contact->id_str == "")
+ return(-1);
+
+ $avatar = twitter_fix_avatar($contact->profile_image_url_https);
+
+ if (function_exists("update_gcontact"))
+ update_gcontact(array("url" => "https://twitter.com/".$contact->screen_name,
+ "network" => NETWORK_TWITTER, "photo" => $avatar, "hide" => true,
+ "name" => $contact->name, "nick" => $contact->screen_name,
+ "location" => $contact->location, "about" => $contact->description,
+ "addr" => $contact->screen_name."@twitter.com", "generation" => 2));
+ else {
+ // Old Code
+ $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
+ dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
+
+ if (count($r) == 0)
+ q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
+ dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
+ dbesc($contact->name),
+ dbesc($contact->screen_name),
+ dbesc($avatar));
+ else
+ q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
+ dbesc($contact->name),
+ dbesc($contact->screen_name),
+ dbesc($avatar),
+ dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
+
+ if (DB_UPDATE_VERSION >= "1177")
+ q("UPDATE `unique_contacts` SET `location` = '%s', `about` = '%s' WHERE url = '%s'",
+ dbesc($contact->location),
+ dbesc($contact->description),
+ dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
+ }
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
intval($uid), dbesc("twitter::".$contact->id_str));
q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
`name`, `nick`, `photo`, `network`, `rel`, `priority`,
`writable`, `blocked`, `readonly`, `pending` )
- VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
+ VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0) ",
intval($uid),
dbesc(datetime_convert()),
dbesc("https://twitter.com/".$contact->screen_name),
intval($contact_id)
);
+ if (DB_UPDATE_VERSION >= "1177")
+ q("UPDATE `contact` SET `location` = '%s',
+ `about` = '%s'
+ WHERE `id` = %d",
+ dbesc($contact->location),
+ dbesc($contact->description),
+ intval($contact_id)
+ );
+
} else {
// update profile photos once every two weeks as we have no notification of when they change.
dbesc($contact->screen_name),
intval($r[0]['id'])
);
+
+ if (DB_UPDATE_VERSION >= "1177")
+ q("UPDATE `contact` SET `location` = '%s',
+ `about` = '%s'
+ WHERE `id` = %d",
+ dbesc($contact->location),
+ dbesc($contact->description),
+ intval($r[0]['id'])
+ );
}
}
if (($footer == "") AND ($picture != ""))
$body .= "\n\n[img]".$picture."[/img]\n";
+ elseif (($footer == "") AND ($picture == ""))
+ $body = add_page_info_to_body($body);
if ($no_tags)
return(array("body" => $body, "tags" => ""));
$postarray['owner-name'] = $post->user->name;
$postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
- $postarray['owner-avatar'] = $post->user->profile_image_url_https;
+ $postarray['owner-avatar'] = twitter_fix_avatar($post->user->profile_image_url_https);
}
if(($contactid == 0) AND !$only_existing_contact)
$postarray['body'] = "[share author='".$post->retweeted_status->user->name.
"' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
"' avatar='".$post->retweeted_status->user->profile_image_url_https.
+ "' posted='".datetime_convert('UTC','UTC',$post->retweeted_status->created_at).
"' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
$postarray['body'];
$postarray['body'] .= "[/share]";
// Let retweets look like wall-to-wall posts
$postarray['author-name'] = $post->retweeted_status->user->name;
$postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
- $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url_https;
+ $postarray['author-avatar'] = twitter_fix_avatar($post->retweeted_status->user->profile_image_url_https);
//if (($post->retweeted_status->user->screen_name != "") AND ($post->retweeted_status->id_str != "")) {
// $postarray['plink'] = "https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str;
// $postarray['uri'] = "twitter::".$post->retweeted_status->id_str;
}
}
+function twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id) {
+ logger("twitter_fetchparentposts: Fetching for user ".$uid." and post ".$post->id_str, LOGGER_DEBUG);
+
+ $posts = array();
+
+ while ($post->in_reply_to_status_id_str != "") {
+ $parameters = array("trim_user" => false, "id" => $post->in_reply_to_status_id_str);
+
+ $post = $connection->get('statuses/show', $parameters);
+
+ if (!count($post)) {
+ logger("twitter_fetchparentposts: Can't fetch post ".$parameters->id, LOGGER_DEBUG);
+ break;
+ }
+
+ $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+ dbesc("twitter::".$post->id_str),
+ intval($uid)
+ );
+
+ if (count($r))
+ break;
+
+ $posts[] = $post;
+ }
+
+ logger("twitter_fetchparentposts: Fetching ".count($posts)." parents", LOGGER_DEBUG);
+
+ $posts = array_reverse($posts);
+
+ if (count($posts)) {
+ foreach ($posts as $post) {
+ $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
+
+ if (trim($postarray['body']) == "")
+ continue;
+
+ $item = item_store($postarray);
+ $postarray["id"] = $item;
+
+ logger('twitter_fetchparentpost: User '.$self["nick"].' posted parent timeline item '.$item);
+
+ if ($item AND !function_exists("check_item_notification"))
+ twitter_checknotification($a, $uid, $own_id, $item, $postarray);
+ }
+ }
+}
+
function twitter_fetchhometimeline($a, $uid) {
$ckey = get_config('twitter', 'consumerkey');
$csecret = get_config('twitter', 'consumersecret');
$otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
$osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
$create_user = get_pconfig($uid, 'twitter', 'create_user');
+ $mirror_posts = get_pconfig($uid, 'twitter', 'mirror_posts');
logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
+ $application_name = get_config('twitter', 'application_name');
+
+ if ($application_name == "")
+ $application_name = $a->get_hostname();
+
require_once('library/twitteroauth.php');
require_once('include/items.php');
if (count($posts)) {
foreach ($posts as $post) {
- if ($post->id_str > $lastid)
+ if ($post->id_str > $lastid) {
$lastid = $post->id_str;
+ set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
+ }
if ($first_time)
continue;
+ if (stristr($post->source, $application_name) && $post->user->screen_name == $own_id) {
+ logger("twitter_fetchhometimeline: Skip previously sended post", LOGGER_DEBUG);
+ continue;
+ }
+
+ if ($mirror_posts && $post->user->screen_name == $own_id && $post->in_reply_to_status_id_str == "") {
+ logger("twitter_fetchhometimeline: Skip post that will be mirrored", LOGGER_DEBUG);
+ continue;
+ }
+
+ if ($post->in_reply_to_status_id_str != "")
+ twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
+
$postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
if (trim($postarray['body']) == "")
continue;
$item = item_store($postarray);
+ $postarray["id"] = $item;
logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
- if ($item != 0)
+ if ($item AND !function_exists("check_item_notification"))
twitter_checknotification($a, $uid, $own_id, $item, $postarray);
}
if ($first_time)
continue;
+ if ($post->in_reply_to_status_id_str != "")
+ twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
+
$postarray = twitter_createpost($a, $uid, $post, $self, false, false);
if (trim($postarray['body']) == "")
continue;
$item = item_store($postarray);
+ $postarray["id"] = $item;
+
+ if ($item AND function_exists("check_item_notification"))
+ check_item_notification($item, $uid, NOTIFY_TAGSELF);
if (!isset($postarray["parent"]) OR ($postarray["parent"] == 0))
$postarray["parent"] = $item;
} else
$parent_id = $postarray['parent'];
- if ($item != 0) {
+ if (($item != 0) AND !function_exists("check_item_notification")) {
require_once('include/enotify.php');
notification(array(
'type' => NOTIFY_TAGSELF,