From 9e7f06ed4407cc177eab918cf5ec0a9c6ab80202 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 22 Apr 2023 10:01:09 +0000 Subject: [PATCH] Tumblr: Dashboard import and activities are working --- tumblr/lang/C/messages.po | 52 +++++++------- tumblr/tumblr.php | 143 ++++++++++++++++++++++++++++++++------ 2 files changed, 151 insertions(+), 44 deletions(-) diff --git a/tumblr/lang/C/messages.po b/tumblr/lang/C/messages.po index 83434406..f3c2fc63 100644 --- a/tumblr/lang/C/messages.po +++ b/tumblr/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-11-21 19:17-0500\n" +"POT-Creation-Date: 2023-04-22 10:00+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,54 +17,58 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: tumblr.php:39 +#: tumblr.php:60 msgid "Permission denied." msgstr "" -#: tumblr.php:69 +#: tumblr.php:111 +msgid "Could not connect to Tumblr. Refresh the page or try again later." +msgstr "" + +#: tumblr.php:159 +msgid "Unable to authenticate" +msgstr "" + +#: tumblr.php:174 msgid "Save Settings" msgstr "" -#: tumblr.php:71 +#: tumblr.php:176 msgid "Consumer Key" msgstr "" -#: tumblr.php:72 +#: tumblr.php:177 msgid "Consumer Secret" msgstr "" -#: tumblr.php:177 -msgid "You are now authenticated to tumblr." -msgstr "" - -#: tumblr.php:178 -msgid "return to the connector page" -msgstr "" - -#: tumblr.php:194 -msgid "Post to Tumblr" -msgstr "" - -#: tumblr.php:225 +#: tumblr.php:212 msgid "Post to page:" msgstr "" -#: tumblr.php:231 +#: tumblr.php:218 msgid "(Re-)Authenticate your tumblr page" msgstr "" -#: tumblr.php:232 +#: tumblr.php:219 msgid "You are not authenticated to tumblr" msgstr "" -#: tumblr.php:237 +#: tumblr.php:224 msgid "Enable Tumblr Post Addon" msgstr "" -#: tumblr.php:238 +#: tumblr.php:225 msgid "Post to Tumblr by default" msgstr "" -#: tumblr.php:244 -msgid "Tumblr Export" +#: tumblr.php:226 +msgid "Import the remote timeline" +msgstr "" + +#: tumblr.php:232 +msgid "Tumblr Import/Export" +msgstr "" + +#: tumblr.php:250 +msgid "Post to Tumblr" msgstr "" diff --git a/tumblr/tumblr.php b/tumblr/tumblr.php index 606e73d1..88ae748b 100644 --- a/tumblr/tumblr.php +++ b/tumblr/tumblr.php @@ -229,7 +229,7 @@ function tumblr_settings(array &$data) $data = [ 'connector' => 'tumblr', - 'title' => DI::l10n()->t('Tumblr Export'), + 'title' => DI::l10n()->t('Tumblr Import/Export'), 'image' => 'images/tumblr.png', 'enabled' => $enabled, 'html' => $html, @@ -272,10 +272,22 @@ function tumblr_hook_fork(array &$b) $post = $b['data']; - if ( - $post['deleted'] || $post['private'] || ($post['created'] !== $post['edited']) || - !strstr($post['postopts'] ?? '', 'tumblr') || ($post['parent'] != $post['id']) - ) { + // Editing is not supported by the addon + if (($post['created'] !== $post['edited']) && !$post['deleted']) { + DI::logger()->info('Editing is not supported by the addon'); + $b['execute'] = false; + return; + } + + if (DI::pConfig()->get($post['uid'], 'tumblr', 'import')) { + // Don't post if it isn't a reply to a tumblr post + if (($post['parent'] != $post['id']) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::TUMBLR])) { + Logger::notice('No tumblr parent found', ['item' => $post['id']]); + $b['execute'] = false; + return; + } + } elseif (!strstr($post['postopts'] ?? '', 'tumblr') || ($post['parent'] != $post['id']) || $post['private']) { + DI::logger()->info('Activities are never exported when we don\'t import the tumblr timeline'); $b['execute'] = false; return; } @@ -283,8 +295,6 @@ function tumblr_hook_fork(array &$b) function tumblr_post_local(array &$b) { - // This can probably be changed to allow editing by pointing to a different API endpoint - if ($b['edit']) { return; } @@ -318,15 +328,63 @@ function tumblr_post_local(array &$b) function tumblr_send(array &$b) { - if ($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited'])) { - return; - } - - if (!strstr($b['postopts'], 'tumblr')) { + if (($b['created'] !== $b['edited']) && !$b['deleted']) { return; } if ($b['gravity'] != Item::GRAVITY_PARENT) { + Logger::debug('Got comment', ['item' => $b]); + + $parent = tumblr_get_post_from_uri($b['thr-parent']); + if (empty($parent)) { + Logger::notice('No tumblr post', ['thr-parent' => $b['thr-parent']]); + return; + } + + Logger::debug('Parent found', ['parent' => $parent]); + + $connection = tumblr_connection($b['uid']); + if (empty($connection)) { + return; + } + + $page = tumblr_get_page($b['uid']); + + if ($b['gravity'] == Item::GRAVITY_COMMENT) { + Logger::notice('Commenting is not supported (yet)'); + } else { + if (($b['verb'] == Activity::LIKE) && !$b['deleted']) { + $params = ['id' => $parent['id'], 'reblog_key' => $parent['reblog_key']]; + $result = $connection->post('user/like', $params); + } elseif (($b['verb'] == Activity::LIKE) && $b['deleted']) { + $params = ['id' => $parent['id'], 'reblog_key' => $parent['reblog_key']]; + $result = $connection->post('user/unlike', $params); + } elseif (($b['verb'] == Activity::ANNOUNCE) && !$b['deleted']) { + $params = ['id' => $parent['id'], 'reblog_key' => $parent['reblog_key']]; + $result = $connection->post('blog/' . $page . '/post/reblog', $params); + } elseif (($b['verb'] == Activity::ANNOUNCE) && $b['deleted']) { + $announce = tumblr_get_post_from_uri($b['extid']); + if (empty($announce)) { + return; + } + $params = ['id' => $announce['id']]; + $result = $connection->post('blog/' . $page . '/post/delete', $params); + } else { + // Unsupported activity + return; + } + + if ($result->meta->status < 400) { + Logger::info('Successfully performed activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response]); + if (!$b['deleted'] && !empty($result->response->id_string)) { + Item::update(['extid' => 'tumblr::' . $result->response->id_string], ['id' => $b['id']]); + } + } else { + Logger::notice('Error while performing activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]); + } + } + return; + } elseif ($b['private'] || !strstr($b['postopts'], 'tumblr')) { return; } @@ -421,6 +479,20 @@ function tumblr_send(array &$b) } } +function tumblr_get_post_from_uri(string $uri): array +{ + $parts = explode(':', $uri); + if (($parts[0] != 'tumblr') || empty($parts[2])) { + return []; + } + + $post ['id'] = $parts[2]; + $post['reblog_key'] = $parts[3] ?? ''; + + $post['reblog_key'] = str_replace('@t', '', $post['reblog_key']); // Temp + return $post; +} + function tumblr_send_npf(array $post): bool { $page = tumblr_get_page($post['uid']); @@ -537,6 +609,15 @@ function tumblr_add_npf_data(string $html, string $plink): string tumblr_replace_with_npf($doc, $node, '[youtube]' . $attributes['data-url'] . '[/youtube]'); } + $list = $xpath->query('//figure[@data-npf]'); + foreach ($list as $node) { + $data = tumblr_get_npf_data($node); + if (empty($data)) { + continue; + } + tumblr_replace_with_npf($doc, $node, tumblr_get_type_replacement($data, $plink)); + } + return $doc->saveHTML(); } @@ -552,8 +633,15 @@ function tumblr_get_type_replacement(array $data, string $plink): string break; case 'link': - $body = PageInfo::getFooterFromUrl($data['url']); + $body = PageInfo::getFooterFromUrl(str_replace('https://href.li/?', '', $data['url'])); + break; + case 'video': + if (!empty($data['url']) && ($data['provider'] == 'tumblr')) { + $body = '[video]' . $data['url'] . '[/video]'; + break; + } + default: Logger::notice('Unknown type', ['type' => $data['type'], 'data' => $data, 'plink' => $plink]); $body = ''; @@ -583,6 +671,9 @@ function tumblr_get_npf_data(DOMNode $node): array function tumblr_replace_with_npf(DOMDocument $doc, DOMNode $node, string $replacement) { + if (empty($replacement)) { + return; + } $replace = $doc->createTextNode($replacement); $node->parentNode->insertBefore($replace, $node); $node->parentNode->removeChild($node); @@ -611,12 +702,14 @@ function tumblr_fetch_dashboard(int $uid) } foreach (array_reverse($dashboard->response->posts) as $post) { - $uri = 'tumblr::' . $post->id_string; + $uri = 'tumblr::' . $post->id_string . ':' . $post->reblog_key; if ($post->id > $last) { $last = $post->id; } + Logger::debug('Importing post', ['uid' => $uid, 'created' => date(DateTimeFormat::MYSQL, $post->timestamp), 'uri' => $uri]); + if (Post::exists(['uri' => $uri, 'uid' => $uid]) || ($post->blog->uuid == $page)) { DI::pConfig()->set($uid, 'tumblr', 'last_id', $last); continue; @@ -625,7 +718,18 @@ function tumblr_fetch_dashboard(int $uid) $item = tumblr_get_header($post, $uri, $uid); $item = tumblr_get_content($item, $post); - item::insert($item); + + $id = item::insert($item); + + 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); + } + } + } DI::pConfig()->set($uid, 'tumblr', 'last_id', $last); } @@ -653,8 +757,6 @@ function tumblr_get_header(stdClass $post, string $uri, int $uid): array $item['owner-link'] = $item['author-link']; $item['owner-avatar'] = $item['author-avatar']; - // @todo process $post->tags; - return $item; } @@ -782,7 +884,7 @@ function tumblr_insert_contact(stdClass $blog, int $uid) 'poll' => 'tumblr::' . $blog->uuid, 'baseurl' => $baseurl, 'priority' => 1, - 'writable' => false, // @todo Allow interaction at a later point in time + 'writable' => true, 'blocked' => false, 'readonly' => false, 'pending' => false, @@ -825,15 +927,16 @@ function tumblr_update_contact(stdClass $blog, int $uid, int $cid, int $pcid) $rel = Contact::NOTHING; } + $uri_id = ItemURI::getIdByURI($url); $fields = [ 'url' => $url, 'nurl' => Strings::normaliseLink($url), - 'uri-id' => ItemURI::getIdByURI($url), + 'uri-id' => $uri_id, 'alias' => $info->response->blog->url, 'name' => $info->response->blog->title, 'nick' => $info->response->blog->name, 'addr' => $info->response->blog->name . '@tumblr.com', - 'about' => $info->response->blog->description, + 'about' => BBCode::convertForUriId($uri_id, $info->response->blog->description, BBCode::CONNECTORS), 'updated' => date(DateTimeFormat::MYSQL, $info->response->blog->updated), 'header' => $info->response->blog->theme->header_image_focused, 'rel' => $rel,