diff options
Diffstat (limited to 'Zotlabs/Lib/Activity.php')
-rw-r--r-- | Zotlabs/Lib/Activity.php | 721 |
1 files changed, 614 insertions, 107 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 6ddbbb9db..232d845c7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2,36 +2,89 @@ namespace Zotlabs\Lib; -use Zotlabs\Lib\Libzot; -use Zotlabs\Lib\Libsync; -use Zotlabs\Lib\ActivityStreams; -use Zotlabs\Lib\Group; +use Zotlabs\Daemon\Master; +use Zotlabs\Zot6\HTTPSig; class Activity { static function encode_object($x) { + if(($x) && (! is_array($x)) && (substr(trim($x),0,1)) === '{' ) { $x = json_decode($x,true); } - if($x['type'] === ACTIVITY_OBJ_PERSON) { - return self::fetch_person($x); - } - if($x['type'] === ACTIVITY_OBJ_PROFILE) { - return self::fetch_profile($x); + + if(is_array($x)) { + + if(array_key_exists('asld',$x)) { + return $x['asld']; + } + + if($x['type'] === ACTIVITY_OBJ_PERSON) { + return self::fetch_person($x); + } + if($x['type'] === ACTIVITY_OBJ_PROFILE) { + return self::fetch_profile($x); + } + if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { + return self::fetch_item($x); + } + if($x['type'] === ACTIVITY_OBJ_THING) { + return self::fetch_thing($x); + } + if($x['type'] === ACTIVITY_OBJ_EVENT) { + return self::fetch_event($x); + } + if($x['type'] === ACTIVITY_OBJ_PHOTO) { + return self::fetch_image($x); + } } - if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { - return self::fetch_item($x); + + return $x; + + } + + static function fetch($url,$channel = null) { + $redirects = 0; + if(! check_siteallowed($url)) { + logger('blacklisted: ' . $url); + return null; } - if($x['type'] === ACTIVITY_OBJ_THING) { - return self::fetch_thing($x); + if(! $channel) { + $channel = get_sys_channel(); } - return $x; + logger('fetch: ' . $url, LOGGER_DEBUG); + if(strpos($url,'x-zot:') === 0) { + $x = ZotURL::fetch($url,$channel); + } + else { + $m = parse_url($url); + $headers = [ + 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Host' => $m['host'], + '(request-target)' => 'get ' . get_request_string($url), + 'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC' + ]; + $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); + $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); + } + + if($x['success']) { + $y = json_decode($x['body'],true); + logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); + return json_decode($x['body'], true); + } + else { + logger('fetch failed: ' . $url); + } + return null; } + + static function fetch_person($x) { return self::fetch_profile($x); } @@ -93,6 +146,73 @@ class Activity { } } + + static function fetch_image($x) { + + + $ret = [ + 'type' => 'Image', + 'id' => $x['id'], + 'name' => $x['title'], + 'content' => bbcode($x['body'], [ 'cache' => true ]), + 'source' => [ 'mediaType' => 'text/bbcode', 'content' => $x['body'] ], + 'published' => datetime_convert('UTC','UTC',$x['created'],ATOM_TIME), + 'updated' => datetime_convert('UTC','UTC', $x['edited'],ATOM_TIME), + 'url' => [ + 'type' => 'Link', + 'mediaType' => $x['link'][0]['type'], + 'href' => $x['link'][0]['href'], + 'width' => $x['link'][0]['width'], + 'height' => $x['link'][0]['height'] + ] + ]; + return $ret; + } + + static function fetch_event($x) { + + // convert old Zot event objects to ActivityStreams Event objects + + if (array_key_exists('content',$x) && array_key_exists('dtstart',$x)) { + $ev = bbtoevent($x['content']); + if($ev) { + + $actor = null; + if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) { + $actor = $x['author']['link'][0]['href']; + } + $y = [ + 'type' => 'Event', + 'id' => z_root() . '/event/' . $ev['event_hash'], + 'summary' => bbcode($ev['summary'], [ 'cache' => true ]), + // RFC3339 Section 4.3 + 'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')), + 'content' => bbcode($ev['description'], [ 'cache' => true ]), + 'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ], + 'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ], + 'actor' => $actor, + ]; + if(! $ev['nofinish']) { + $y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00')); + } + + // copy attachments from the passed object - these are already formatted for ActivityStreams + + if($x['attachment']) { + $y['attachment'] = $x['attachment']; + } + + if($actor) { + return $y; + } + } + } + + return $x; + + } + + static function encode_item_collection($items,$id,$type,$extra = null) { $ret = [ @@ -167,7 +287,7 @@ class Activity { $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid'])); if($i['title']) - $ret['title'] = bbcode($i['title']); + $ret['name'] = $i['title']; $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); if($i['created'] !== $i['edited']) @@ -190,15 +310,15 @@ class Activity { $ret['attributedTo'] = $i['author']['xchan_url']; if($i['id'] != $i['parent']) { - $ret['inReplyTo'] = ((strpos($i['parent_mid'],'http') === 0) ? $i['parent_mid'] : z_root() . '/item/' . urlencode($i['parent_mid'])); + $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); } if($i['mimetype'] === 'text/bbcode') { if($i['title']) - $ret['name'] = bbcode($i['title']); + $ret['name'] = bbcode($i['title'], [ 'cache' => true ]); if($i['summary']) - $ret['summary'] = bbcode($i['summary']); - $ret['content'] = bbcode($i['body']); + $ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]); + $ret['content'] = bbcode($i['body'], [ 'cache' => true ]); $ret['source'] = [ 'content' => $i['body'], 'mediaType' => 'text/bbcode' ]; } @@ -291,7 +411,7 @@ class Activity { $ret = []; if($item['attach']) { - $atts = json_decode($item['attach'],true); + $atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'],true)); if($atts) { foreach($atts as $att) { if(strpos($att['type'],'image')) { @@ -303,7 +423,7 @@ class Activity { } } } - + return $ret; } @@ -342,21 +462,28 @@ class Activity { $ret['type'] = 'Tombstone'; $ret['formerType'] = self::activity_obj_mapper($i['obj_type']); $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid'])); + $actor = self::encode_person($i['author'],false); + if($actor) + $ret['actor'] = $actor; + else + return []; return $ret; } $ret['type'] = self::activity_mapper($i['verb']); + + $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid'])); if($i['title']) - $ret['name'] = html2plain(bbcode($i['title'])); + $ret['name'] = html2plain(bbcode($i['title'], [ 'cache' => true ])); if($i['summary']) - $ret['summary'] = bbcode($i['summary']); + $ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]); if($ret['type'] === 'Announce') { $tmp = preg_replace('/\[share(.*?)\[\/share\]/ism',EMPTY_STR, $i['body']); - $ret['content'] = bbcode($tmp); + $ret['content'] = bbcode($tmp, [ 'cache' => true ]); $ret['source'] = [ 'content' => $i['body'], 'mediaType' => 'text/bbcode' @@ -382,7 +509,7 @@ class Activity { } if($i['id'] != $i['parent']) { - $ret['inReplyTo'] = ((strpos($i['parent_mid'],'http') === 0) ? $i['parent_mid'] : z_root() . '/item/' . urlencode($i['parent_mid'])); + $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); $reply = true; if($i['item_private']) { @@ -413,10 +540,18 @@ class Activity { else return []; + if(strpos($i['body'],'[/share]') !== false) { + $i['obj'] = null; + } + if($i['obj']) { if(! is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'],true); } + if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { + $i['obj']['id'] = $i['id']; + } + $obj = self::encode_object($i['obj']); if($obj) $ret['object'] = $obj; @@ -431,6 +566,7 @@ class Activity { return []; } + if($i['target']) { if(! is_array($i['target'])) { $i['target'] = json_decode($i['target'],true); @@ -540,6 +676,12 @@ class Activity { } + + + + + + static function activity_mapper($verb) { if(strpos($verb,'/') === false) { @@ -556,6 +698,9 @@ class Activity { 'http://activitystrea.ms/schema/1.0/tag' => 'Add', 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', + 'http://purl.org/zot/activity/attendyes' => 'Accept', + 'http://purl.org/zot/activity/attendno' => 'Reject', + 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' ]; @@ -566,7 +711,7 @@ class Activity { // Reactions will just map to normal activities if(strpos($verb,ACTIVITY_REACT) !== false) - return 'Create'; + return 'emojiReaction'; if(strpos($verb,ACTIVITY_MOOD) !== false) return 'Create'; @@ -582,6 +727,70 @@ class Activity { } + + static function activity_decode_mapper($verb) { + + $acts = [ + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', + 'http://purl.org/zot/activity/attendyes' => 'Accept', + 'http://purl.org/zot/activity/attendno' => 'Reject', + 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' + ]; + + + foreach($acts as $k => $v) { + if($verb === $v) { + return $k; + } + } + + logger('Unmapped activity: ' . $verb); + return 'Create'; + + } + + static function activity_obj_decode_mapper($obj) { + + $objs = [ + 'http://activitystrea.ms/schema/1.0/note' => 'Note', + 'http://activitystrea.ms/schema/1.0/note' => 'Article', + 'http://activitystrea.ms/schema/1.0/comment' => 'Note', + 'http://activitystrea.ms/schema/1.0/person' => 'Person', + 'http://purl.org/zot/activity/profile' => 'Profile', + 'http://activitystrea.ms/schema/1.0/photo' => 'Image', + 'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon', + 'http://activitystrea.ms/schema/1.0/event' => 'Event', + 'http://activitystrea.ms/schema/1.0/wiki' => 'Document', + 'http://purl.org/zot/activity/location' => 'Place', + 'http://purl.org/zot/activity/chessgame' => 'Game', + 'http://purl.org/zot/activity/tagterm' => 'zot:Tag', + 'http://purl.org/zot/activity/thing' => 'Object', + 'http://purl.org/zot/activity/file' => 'zot:File', + 'http://purl.org/zot/activity/mood' => 'zot:Mood', + + ]; + + foreach($objs as $k => $v) { + if($obj === $v) { + return $k; + } + } + + logger('Unmapped activity object: ' . $obj); + return 'Note'; + } + + + + static function activity_obj_mapper($obj) { if(strpos($obj,'/') === false) { @@ -678,7 +887,7 @@ class Activity { // Send an Accept back to them set_abconfig($channel['channel_id'],$person_obj['id'],'pubcrawl','their_follow_id', $their_follow_id); - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); return; case 'Accept': @@ -779,9 +988,9 @@ class Activity { if($my_perms && $automatic) { // send an Accept for this Follow activity - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); // Send back a Follow notification to them - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); } $clone = array(); @@ -972,7 +1181,7 @@ class Activity { $photos = import_xchan_photo($icon,$url); $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), + dbescdate(datetime_convert('UTC','UTC',$photos[5])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -1149,7 +1358,7 @@ class Activity { } if($act->obj['type'] === 'Note' && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach']); + $s['body'] .= self::bb_attach($s['attach'],$s['body']); } // we will need a hook here to extract magnet links e.g. peertube @@ -1216,7 +1425,7 @@ class Activity { if($parent) { if($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(array('Notifier','comment-import',$x['item_id'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) @@ -1230,21 +1439,39 @@ class Activity { } + static function get_actor_bbmention($id) { - static function decode_note($act) { + $x = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' or hubloc_id_url = '%s' limit 1", + dbesc($id), + dbesc($id) + ); - $s = []; + if($x) { + return sprintf('@[zrl=%s]%s[/zrl]',$x[0]['xchan_url'],$x[0]['xchan_name']); + } + return '@{' . $id . '}'; + + } + static function decode_note($act) { - $content = self::get_content($act->obj); + $response_activity = false; + + $s = []; + if(is_array($act->obj)) { + $content = self::get_content($act->obj); + } + $s['owner_xchan'] = $act->actor['id']; $s['author_xchan'] = $act->actor['id']; - $s['mid'] = $act->id; - $s['parent_mid'] = $act->parent_id; + // ensure we store the original actor + self::actor_store($act->actor['id'],$act->actor); + $s['mid'] = $act->obj['id']; + $s['parent_mid'] = $act->parent_id; if($act->data['published']) { $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); @@ -1259,110 +1486,333 @@ class Activity { $s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']); } - if(! $s['created']) - $s['created'] = datetime_convert(); - if(! $s['edited']) - $s['edited'] = $s['created']; + if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) { - if(in_array($act->type,['Announce'])) { - $root_content = self::get_content($act->raw); + $response_activity = true; - $s['title'] = self::bb_content($root_content,'name'); - $s['summary'] = self::bb_content($root_content,'summary'); - $s['body'] = (self::bb_content($root_content,'bbcode') ? : self::bb_content($root_content,'content')); + $s['mid'] = $act->id; + $s['parent_mid'] = $act->obj['id']; - if(strpos($s['body'],'[share') === false) { + // over-ride the object timestamp with the activity - // @fixme - error check and set defaults + if($act->data['published']) { + $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); + } - $name = urlencode($act->obj['actor']['name']); - $profile = $act->obj['actor']['id']; - $photo = $act->obj['icon']['url']; + if($act->data['updated']) { + $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); + } - $s['body'] .= "\r\n[share author='" . $name . - "' profile='" . $profile . - "' avatar='" . $photo . - "' link='" . $act->obj['id'] . - "' auth='" . ((is_matrix_url($act->obj['id'])) ? 'true' : 'false' ) . - "' posted='" . $act->obj['published'] . - "' message_id='" . $act->obj['id'] . - "']"; + $obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj)); + // ensure we store the original actor + self::actor_store($obj_actor['id'],$obj_actor); + + $mention = self::get_actor_bbmention($obj_actor['id']); + + if($act->type === 'Like') { + $content['content'] = sprintf( t('Likes %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; } - } - else { - $s['title'] = self::bb_content($content,'name'); - $s['summary'] = self::bb_content($content,'summary'); - $s['body'] = (self::bb_content($content,'bbcode') ? : self::bb_content($content,'content')); + if($act->type === 'Dislike') { + $content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; + } + if($act->type === 'Accept' && $act->obj['type'] === 'Event' ) { + $content['content'] = sprintf( t('Will attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; + } + if($act->type === 'Reject' && $act->obj['type'] === 'Event' ) { + $content['content'] = sprintf( t('Will not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; + } + if($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) { + $content['content'] = sprintf( t('May attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content']; + } + if($act->type === 'Announce') { + $content['content'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); + } + if ($act->type === 'emojiReaction') { + $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); + } } - $s['verb'] = self::activity_mapper($act->type); + if(! $s['created']) + $s['created'] = datetime_convert(); + + if(! $s['edited']) + $s['edited'] = $s['created']; - if($act->type === 'Tombstone') { + $s['title'] = self::bb_content($content,'name'); + $s['summary'] = self::bb_content($content,'summary'); + $s['body'] = ((self::bb_content($content,'bbcode') && (! $response_activity)) ? self::bb_content($content,'bbcode') : self::bb_content($content,'content')); + + $s['verb'] = self::activity_decode_mapper($act->type); + + + if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { $s['item_deleted'] = 1; } - $s['obj_type'] = self::activity_obj_mapper($act->obj['type']); - $s['obj'] = $act->obj; + $s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']); + if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { + $s['obj_type'] = ACTIVITY_OBJ_COMMENT; + } + + if($act->obj['type'] === 'Event') { + $s['obj'] = []; + $s['obj']['asld'] = $act->obj; + $s['obj']['type'] = ACTIVITY_OBJ_EVENT; + $s['obj']['id'] = $act->obj['id']; + $s['obj']['title'] = $act->obj['summary']; + + if(strpos($act->obj['startTime'],'Z')) + $s['obj']['adjust'] = true; + else + $s['obj']['adjust'] = false; + + $s['obj']['dtstart'] = datetime_convert('UTC','UTC',$act->obj['startTime']); + if($act->obj['endTime']) + $s['obj']['dtend'] = datetime_convert('UTC','UTC',$act->obj['endTime']); + else + $s['obj']['nofinish'] = true; + $s['obj']['description'] = $act->obj['content']; + + if(array_path_exists('location/content',$act->obj)) + $s['obj']['location'] = $act->obj['location']['content']; + + } + else { + $s['obj'] = $act->obj; + } $instrument = $act->get_property_obj('instrument'); - if(! $instrument) + if((! $instrument) && (! $response_activity)) { $instrument = $act->get_property_obj('instrument',$act->obj); + } if($instrument && array_key_exists('type',$instrument) && $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) { $s['app'] = escape_tags($instrument['name']); } - $a = self::decode_taxonomy($act->obj); - if($a) { - $s['term'] = $a; + + if(! $response_activity) { + $a = self::decode_taxonomy($act->obj); + if($a) { + $s['term'] = $a; + foreach($a as $b) { + if($b['ttype'] === TERM_EMOJI) { + $s['title'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['title']); + $s['summary'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['summary']); + $s['body'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['body']); + } + } + } + + $a = self::decode_attachment($act->obj); + if($a) { + $s['attach'] = $a; + } } - $a = self::decode_attachment($act->obj); - if($a) { - $s['attach'] = $a; + if($act->obj['type'] === 'Note' && $s['attach']) { + $s['body'] .= self::bb_attach($s['attach'],$s['body']); } + // we will need a hook here to extract magnet links e.g. peertube // right now just link to the largest mp4 we find that will fit in our // standard content region - if($act->obj['type'] === 'Video') { + if(! $response_activity) { + if($act->obj['type'] === 'Video') { - $vtypes = [ - 'video/mp4', - 'video/ogg', - 'video/webm' - ]; + $vtypes = [ + 'video/mp4', + 'video/ogg', + 'video/webm' + ]; - $mps = []; - if(array_key_exists('url',$act->obj) && is_array($act->obj['url'])) { - foreach($act->obj['url'] as $vurl) { - if(in_array($vurl['mimeType'], $vtypes)) { - if(! array_key_exists('width',$vurl)) { - $vurl['width'] = 0; + $mps = []; + $ptr = null; + + if(array_key_exists('url',$act->obj)) { + if(is_array($act->obj['url'])) { + if(array_key_exists(0,$act->obj['url'])) { + $ptr = $act->obj['url']; + } + else { + $ptr = [ $act->obj['url'] ]; + } + foreach($ptr as $vurl) { + // peertube uses the non-standard element name 'mimeType' here + if(array_key_exists('mimeType',$vurl)) { + if(in_array($vurl['mimeType'], $vtypes)) { + if(! array_key_exists('width',$vurl)) { + $vurl['width'] = 0; + } + $mps[] = $vurl; + } + } + elseif(array_key_exists('mediaType',$vurl)) { + if(in_array($vurl['mediaType'], $vtypes)) { + if(! array_key_exists('width',$vurl)) { + $vurl['width'] = 0; + } + $mps[] = $vurl; + } + } + } + } + if($mps) { + usort($mps,[ __CLASS__, 'vid_sort' ]); + foreach($mps as $m) { + if(intval($m['width']) < 500 && self::media_not_in_body($m['href'],$s['body'])) { + $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; + break; + } } - $mps[] = $vurl; + } + elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { + $s['body'] .= "\n\n" . '[video]' . $act->obj['url'] . '[/video]'; } } } - if($mps) { - usort($mps,'as_vid_sort'); - foreach($mps as $m) { - if(intval($m['width']) < 500) { - $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; - break; + + if($act->obj['type'] === 'Audio') { + + $atypes = [ + 'audio/mpeg', + 'audio/ogg', + 'audio/wav' + ]; + + $ptr = null; + + if(array_key_exists('url',$act->obj)) { + if(is_array($act->obj['url'])) { + if(array_key_exists(0,$act->obj['url'])) { + $ptr = $act->obj['url']; + } + else { + $ptr = [ $act->obj['url'] ]; + } + foreach($ptr as $vurl) { + if(in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) { + $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; + break; + } + } + } + elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { + $s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]'; + } + } + + } + + // avoid double images from hubzilla to zap/osada + + if($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) { + + $ptr = null; + + if(array_key_exists('url',$act->obj)) { + if(is_array($act->obj['url'])) { + if(array_key_exists(0,$act->obj['url'])) { + $ptr = $act->obj['url']; + } + else { + $ptr = [ $act->obj['url'] ]; + } + foreach($ptr as $vurl) { + if(strpos($s['body'],$vurl['href']) === false) { + $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; + break; + } + } + } + elseif(is_string($act->obj['url'])) { + if(strpos($s['body'],$act->obj['url']) === false) { + $s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]'; + } + } + } + } + + + if($act->obj['type'] === 'Page' && ! $s['body']) { + + $ptr = null; + $purl = EMPTY_STR; + + if(array_key_exists('url',$act->obj)) { + if(is_array($act->obj['url'])) { + if(array_key_exists(0,$act->obj['url'])) { + $ptr = $act->obj['url']; + } + else { + $ptr = [ $act->obj['url'] ]; + } + foreach($ptr as $vurl) { + if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + $purl = $vurl['href']; + break; + } + elseif(array_key_exists('mimeType',$vurl) && $vurl['mimeType'] === 'text/html') { + $purl = $vurl['href']; + break; + } + } + } + elseif(is_string($act->obj['url'])) { + $purl = $act->obj['url']; + } + if($purl) { + $li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl)); + if($li['success'] && $li['body']) { + $s['body'] .= "\n" . $li['body']; + } + else { + $s['body'] .= "\n\n" . $purl; + } } } } } + + + if(in_array($act->obj['type'],[ 'Note','Article','Page' ])) { + $ptr = null; + + if(array_key_exists('url',$act->obj)) { + if(is_array($act->obj['url'])) { + if(array_key_exists(0,$act->obj['url'])) { + $ptr = $act->obj['url']; + } + else { + $ptr = [ $act->obj['url'] ]; + } + foreach($ptr as $vurl) { + if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + $s['plink'] = $vurl['href']; + break; + } + } + } + elseif(is_string($act->obj['url'])) { + $s['plink'] = $act->obj['url']; + } + } + } + + if(! $s['plink']) { + $s['plink'] = $s['mid']; + } + if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) $s['item_private'] = 1; set_iconfig($s,'activitypub','recips',$act->raw_recips); - + // @FIXME: $parent is not defined if($parent) { set_iconfig($s,'activitypub','rawmsg',$act->raw,1); } @@ -1371,8 +1821,6 @@ class Activity { } - - static function announce_note($channel,$observer_hash,$act) { $s = []; @@ -1464,7 +1912,7 @@ class Activity { $body .= self::bb_content($content,'content'); if($act->obj['type'] === 'Note' && $s['attach']) { - $body .= self::bb_attach($s['attach']); + $body .= self::bb_attach($s['attach'],$body); } $body .= "[/share]"; @@ -1495,10 +1943,11 @@ class Activity { if(is_array($x) && $x['item_id']) { + // @FIXME: $parent is not defined if($parent) { if($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(array('Notifier','comment-import',$x['item_id'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) @@ -1634,7 +2083,7 @@ class Activity { if($result['success']) { // if the message isn't already being relayed, notify others if(intval($parent_item['item_origin'])) - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$result['item_id'])); + Master::Summon(array('Notifier','comment-import',$result['item_id'])); sync_an_item($channel['channel_id'],$result['item_id']); } @@ -1642,19 +2091,26 @@ class Activity { } - static function bb_attach($attach) { + + static function bb_attach($attach,$body) { $ret = false; foreach($attach as $a) { if(strpos($a['type'],'image') !== false) { - $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; + if(self::media_not_in_body($a['href'],$body)) { + $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; + } } if(array_key_exists('type',$a) && strpos($a['type'], 'video') === 0) { - $ret .= "\n\n" . '[video]' . $a['href'] . '[/video]'; + if(self::media_not_in_body($a['href'],$body)) { + $ret .= "\n\n" . '[video]' . $a['href'] . '[/video]'; + } } if(array_key_exists('type',$a) && strpos($a['type'], 'audio') === 0) { - $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; + if(self::media_not_in_body($a['href'],$body)) { + $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; + } } } @@ -1662,16 +2118,31 @@ class Activity { } + // check for the existence of existing media link in body + + static function media_not_in_body($s,$body) { + + if((strpos($body,']' . $s . '[/img]') === false) && + (strpos($body,']' . $s . '[/zmg]') === false) && + (strpos($body,']' . $s . '[/video]') === false) && + (strpos($body,']' . $s . '[/audio]') === false)) { + return true; + } + return false; + } + static function bb_content($content,$field) { require_once('include/html2bbcode.php'); - + require_once('include/event.php'); $ret = false; if(is_array($content[$field])) { foreach($content[$field] as $k => $v) { - $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]'; + $ret .= html2bbcode($v); + // save this for auto-translate or dynamic filtering + // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]'; } } else { @@ -1682,6 +2153,9 @@ class Activity { $ret = html2bbcode($content[$field]); } } + if($field === 'content' && $content['event'] && (! strpos($ret,'[event'))) { + $ret .= format_event_bbcode($content['event']); + } return $ret; } @@ -1690,21 +2164,52 @@ class Activity { static function get_content($act) { $content = []; - if (! $act) { + $event = null; + + if ((! $act) || (! is_array($act))) { return $content; } + if($act['type'] === 'Event') { + $adjust = false; + $event = []; + $event['event_hash'] = $act['id']; + if(array_key_exists('startTime',$act) && strpos($act['startTime'],-1,1) === 'Z') { + $adjust = true; + $event['adjust'] = 1; + $event['dtstart'] = datetime_convert('UTC','UTC',$event['startTime'] . (($adjust) ? '' : 'Z')); + } + if(array_key_exists('endTime',$act)) { + $event['dtend'] = datetime_convert('UTC','UTC',$event['endTime'] . (($adjust) ? '' : 'Z')); + } + else { + $event['nofinish'] = true; + } + } + foreach ([ 'name', 'summary', 'content' ] as $a) { if (($x = self::get_textfield($act,$a)) !== false) { $content[$a] = $x; } } + + if($event) { + $event['summary'] = html2bbcode($content['summary']); + $event['description'] = html2bbcode($content['content']); + if($event['summary'] && $event['dtstart']) { + $content['event'] = $event; + } + } + if (array_key_exists('source',$act) && array_key_exists('mediaType',$act['source'])) { if ($act['source']['mediaType'] === 'text/bbcode') { $content['bbcode'] = purify_html($act['source']['content']); } } + + + return $content; } @@ -1722,4 +2227,6 @@ class Activity { } return $content; } + + }
\ No newline at end of file |