]> git.mxchange.org Git - friendica-addons.git/commitdiff
Tumblr: We can now follow, unfollow, add posts, ...
authorMichael <heluecht@pirati.ca>
Wed, 26 Apr 2023 22:15:59 +0000 (22:15 +0000)
committerMichael <heluecht@pirati.ca>
Wed, 26 Apr 2023 22:15:59 +0000 (22:15 +0000)
tumblr/tumblr.php

index 2aa80f3b4e81cab86dccd8c9c75a478bf05e6c2e..2cbf946c75e2f7284b812cd970676248a6d671dc 100644 (file)
@@ -12,6 +12,7 @@ use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
 use Friendica\Content\Text\NPF;
 use Friendica\Core\Cache\Enum\Duration;
+use Friendica\Core\Config\Util\ConfigFileManager;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
@@ -41,6 +42,7 @@ define('TUMBLR_DEFAULT_POLL_INTERVAL', 10); // given in minutes
 
 function tumblr_install()
 {
+       Hook::register('load_config',             __FILE__, 'tumblr_load_config');
        Hook::register('hook_fork',               __FILE__, 'tumblr_hook_fork');
        Hook::register('post_local',              __FILE__, 'tumblr_post_local');
        Hook::register('notifier_normal',         __FILE__, 'tumblr_send');
@@ -48,6 +50,175 @@ function tumblr_install()
        Hook::register('connector_settings',      __FILE__, 'tumblr_settings');
        Hook::register('connector_settings_post', __FILE__, 'tumblr_settings_post');
        Hook::register('cron',                    __FILE__, 'tumblr_cron');
+       Hook::register('support_follow',          __FILE__, 'tumblr_support_follow');
+       Hook::register('follow',                  __FILE__, 'tumblr_follow');
+       Hook::register('unfollow',                __FILE__, 'tumblr_unfollow');
+       Hook::register('block',                   __FILE__, 'tumblr_block');
+       Hook::register('unblock',                 __FILE__, 'tumblr_unblock');
+       Hook::register('check_item_notification', __FILE__, 'tumblr_check_item_notification');
+       Hook::register('probe_detect',            __FILE__, 'tumblr_probe_detect');
+       Hook::register('item_by_link',            __FILE__, 'tumblr_item_by_link');
+       Logger::info('installed tumblr');
+}
+
+function tumblr_load_config(ConfigFileManager $loader)
+{
+       DI::app()->getConfigCache()->load($loader->loadAddonConfig('tumblr'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
+}
+
+function tumblr_check_item_notification(array &$notification_data)
+{
+       if (!tumblr_enabled_for_user($notification_data['uid'])) { 
+               return;
+       }
+
+       $page = tumblr_get_page($notification_data['uid']);
+       if (empty($page)) {
+               return;
+       }
+
+       $own_user = Contact::selectFirst(['url', 'alias'], ['uid' => $notification_data['uid'], 'poll' => 'tumblr::'.$page]);
+       if ($own_user) {
+               $notification_data['profiles'][] = $own_user['url'];
+               $notification_data['profiles'][] = $own_user['alias'];
+       }
+}
+
+function tumblr_probe_detect(array &$hookData)
+{
+       // Don't overwrite an existing result
+       if (isset($hookData['result'])) {
+               return;
+       }
+
+       // Avoid a lookup for the wrong network
+       if (!in_array($hookData['network'], ['', Protocol::TUMBLR])) {
+               return;
+       }
+
+       Logger::debug('Search for tumblr blog', ['url' => $hookData['uri']]);
+
+       $hookData['result'] = tumblr_get_contact_by_url($hookData['uri']);
+}
+
+function tumblr_item_by_link(array &$hookData)
+{
+       // Don't overwrite an existing result
+       if (isset($hookData['item_id'])) {
+               return;
+       }
+
+       if (!tumblr_enabled_for_user($hookData['uid'])) {
+               return;
+       }
+
+       if (!preg_match('#^https?://www\.tumblr.com/blog/view/(.+)/(\d+).*#', $hookData['uri'], $matches) && !preg_match('#^https?://www\.tumblr.com/(.+)/(\d+).*#', $hookData['uri'], $matches)) {
+               return;
+       }
+       
+       Logger::debug('Found tumblr post', ['url' => $hookData['uri'], 'blog' => $matches[1], 'id' => $matches[2]]);
+
+       $parameters = ['id' => $matches[2], 'reblog_info' => false, 'notes_info' => false, 'npf' => false];
+       $result = tumblr_get($hookData['uid'], 'blog/' . $matches[1] . '/posts', $parameters);
+       if ($result->meta->status > 399) {
+               Logger::notice('Error fetching status', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'blog' => $matches[1], 'id' => $matches[2]]);
+               return [];
+       }
+
+       Logger::debug('Got post', ['blog' => $matches[1], 'id' => $matches[2], 'result' => $result->response->posts]);
+       if (!empty($result->response->posts)) {
+               $hookData['item_id'] = tumblr_process_post($result->response->posts[0], $hookData['uid']);
+       }
+}
+
+function tumblr_support_follow(array &$data)
+{
+       if ($data['protocol'] == Protocol::TUMBLR) {
+               $data['result'] = true;
+       }
+}
+
+function tumblr_follow(array &$hook_data)
+{
+       $uid = DI::userSession()->getLocalUserId();
+
+       if (!tumblr_enabled_for_user($uid)) {
+               return;
+       }
+
+       Logger::debug('Check if contact is Tumblr', ['url' => $hook_data['url']]);
+
+       $fields = tumblr_get_contact_by_url($hook_data['url']);
+       if (empty($fields)) {
+               Logger::debug('Contact is not a Tumblr contact', ['url' => $hook_data['url']]);
+               return;
+       }
+
+       $result = tumblr_post($uid, 'user/follow', ['url' => $fields['url']]);
+       if ($result->meta->status <= 399) {
+               $hook_data['contact'] = $fields;
+               Logger::debug('Successfully start following', ['url' => $fields['url']]);
+       } else {
+               Logger::notice('Following failed', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'url' => $fields['url']]);
+       }
+}
+
+function tumblr_unfollow(array &$hook_data)
+{
+       if (!tumblr_enabled_for_user($hook_data['uid'])) {
+               return;
+       }
+
+       if (!tumblr_get_contact_uuid($hook_data['contact'])) {
+               return;
+       }
+       $result = tumblr_post($hook_data['uid'], 'user/unfollow', ['url' => $hook_data['contact']['url']]);
+       $hook_data['result'] = ($result->meta->status <= 399);
+}
+
+function tumblr_block(array &$hook_data)
+{
+       if (!tumblr_enabled_for_user($hook_data['uid'])) {
+               return;
+       }
+
+       $uuid = tumblr_get_contact_uuid($hook_data['contact']);
+       if (!$uuid) {
+               return;
+       }
+
+       $result = tumblr_post($hook_data['uid'], 'blog/' . tumblr_get_page($hook_data['uid']) . '/blocks', ['blocked_tumblelog' => $uuid]);
+       $hook_data['result'] = ($result->meta->status <= 399);
+
+       if ($hook_data['result']) {
+               $cdata = Contact::getPublicAndUserContactID($hook_data['contact']['id'], $hook_data['uid']);
+               if (!empty($cdata['user'])) {
+                       Contact::remove($cdata['user']);
+               }
+       }
+}
+
+function tumblr_unblock(array &$hook_data)
+{
+       if (!tumblr_enabled_for_user($hook_data['uid'])) {
+               return;
+       }
+
+       $uuid = tumblr_get_contact_uuid($hook_data['contact']);
+       if (!$uuid) {
+               return;
+       }
+
+       $result = tumblr_delete($hook_data['uid'], 'blog/' . tumblr_get_page($hook_data['uid']) . '/blocks', ['blocked_tumblelog' => $uuid]);
+       $hook_data['result'] = ($result->meta->status <= 399);
+}
+
+function tumblr_get_contact_uuid(array $contact): string
+{
+       if (($contact['network'] != Protocol::TUMBLR) || (substr($contact['poll'], 0, 8) != 'tumblr::')) {
+               return '';
+       }
+       return substr($contact['poll'], 8);
 }
 
 /**
@@ -544,24 +715,35 @@ function tumblr_fetch_dashboard(int $uid)
                        continue;
                }
 
-               $item = tumblr_get_header($post, $uri, $uid);
+               tumblr_process_post($post, $uid, $uri);
+
+
+               DI::pConfig()->set($uid, 'tumblr', 'last_id', $last);
+       }
+}
+
+function tumblr_process_post(stdClass $post, int $uid, string $uri = ''): int
+{
+       if (empty($uri)) {
+               $uri = 'tumblr::' . $post->id_string . ':' . $post->reblog_key;
+       }
+
+       $item = tumblr_get_header($post, $uri, $uid);
 
-               $item = tumblr_get_content($item, $post);
+       $item = tumblr_get_content($item, $post);
 
-               $id = item::insert($item);
+       $id = item::insert($item);
 
-               if ($id) {
-                       $stored = Post::selectFirst(['uri-id'], ['id' => $id]);
+       if ($id) {
+               $stored = Post::selectFirst(['uri-id'], ['id' => $id]);
 
-                       if (!empty($post->tags)) {
-                               foreach ($post->tags as $tag) {
-                                       Tag::store($stored['uri-id'], Tag::HASHTAG, $tag);
-                               }
+               if (!empty($post->tags)) {
+                       foreach ($post->tags as $tag) {
+                               Tag::store($stored['uri-id'], Tag::HASHTAG, $tag);
                        }
                }
-
-               DI::pConfig()->set($uid, 'tumblr', 'last_id', $last);
        }
+       return $id;
 }
 
 /**
@@ -969,6 +1151,80 @@ function tumblr_get_blogs(int $uid): array
        return $blogs;
 }
 
+function tumblr_enabled_for_user(int $uid) 
+{
+       return !empty($uid) && !empty(DI::pConfig()->get($uid, 'tumblr', 'access_token')) &&
+               !empty(DI::pConfig()->get($uid, 'tumblr', 'refresh_token')) &&
+               !empty(DI::config()->get('tumblr', 'consumer_key')) &&
+               !empty(DI::config()->get('tumblr', 'consumer_secret'));
+}
+
+/**
+ * Get a contact array from a Tumblr url
+ *
+ * @param string $url
+ * @return array
+ */
+function tumblr_get_contact_by_url(string $url): array
+{
+       $consumer_key = DI::config()->get('tumblr', 'consumer_key');
+       if (empty($consumer_key)) {
+               return [];
+       }
+
+       if (!preg_match('#^https?://tumblr.com/(.+)#', $url, $matches) && !preg_match('#^https?://www\.tumblr.com/(.+)#', $url, $matches) && !preg_match('#^https?://(.+)\.tumblr.com#', $url, $matches)) {
+               $curlResult = DI::httpClient()->get($url);
+               $html = $curlResult->getBody();
+               if (empty($html)) {
+                       return [];
+               }
+               $doc = new DOMDocument();
+               @$doc->loadHTML($html);
+               $xpath = new DomXPath($doc);
+               $body = $xpath->query('body');
+               $attributes = tumblr_get_attributes($body->item(0));
+               $blog = $attributes['data-urlencoded-name'] ?? '';
+       } else {
+               $blogs = explode('/', $matches[1]);
+               $blog = $blogs[0] ?? '';
+       }
+
+       if (empty($blog)) {
+               return [];
+       }
+
+       $curlResult = DI::httpClient()->get('https://api.tumblr.com/v2/blog/' . $blog . '/info?api_key=' . $consumer_key);
+       $body = $curlResult->getBody();
+       $data = json_decode($body);
+       if (empty($data)) {
+               return [];
+       }
+
+       $baseurl = 'https://tumblr.com';
+       $url     = $baseurl . '/' . $data->response->blog->name;
+
+       return [
+               'url'      => $url,
+               'nurl'     => Strings::normaliseLink($url),
+               'addr'     => $data->response->blog->name . '@tumblr.com',
+               'alias'    => $data->response->blog->url,
+               'batch'    => '',
+               'notify'   => '',
+               'poll'     => 'tumblr::' . $data->response->blog->uuid,
+               'poco'     => '',
+               'name'     => $data->response->blog->title,
+               'nick'     => $data->response->blog->name,
+               'network'  => Protocol::TUMBLR,
+               'baseurl'  => $baseurl,
+               'pubkey'   => '',
+               'priority' => 0,
+               'guid'     => $data->response->blog->uuid,
+               'about'    => $data->response->blog->description,
+       'photo'    => $data->response->blog->avatar[0]->url,
+       'header'   => $data->response->blog->theme->header_image_focused,
+       ];
+}
+
 /**
  * Perform an OAuth2 GET request
  *
@@ -1005,6 +1261,27 @@ function tumblr_post(int $uid, string $url, array $parameters): stdClass
        return tumblr_format_result($curlResult);
 }
 
+/**
+ * Perform an OAuth2 DELETE request
+ *
+ * @param integer $uid
+ * @param string $url
+ * @param array $parameters
+ * @return stdClass
+ */
+function tumblr_delete(int $uid, string $url, array $parameters): stdClass
+{
+       $url = 'https://api.tumblr.com/v2/' . $url;
+
+       $opts = [
+               HttpClientOptions::HEADERS     => ['Authorization' => ['Bearer ' . tumblr_get_token($uid)]],
+               HttpClientOptions::FORM_PARAMS => $parameters
+       ];
+
+       $curlResult = DI::httpClient()->request('delete', $url, $opts);
+       return tumblr_format_result($curlResult);
+}
+
 /**
  * Format the get/post result value
  *