diff --git a/themes/hugo-mastodon-comments/.gitignore b/themes/hugo-mastodon-comments/.gitignore
index 0ed663d..29e28fb 100644
--- a/themes/hugo-mastodon-comments/.gitignore
+++ b/themes/hugo-mastodon-comments/.gitignore
@@ -1 +1,2 @@
static/comments/config.php
+static/comments/cache-*.json
diff --git a/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php b/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php
deleted file mode 100644
index b57e252..0000000
--- a/themes/hugo-mastodon-comments/static/comments/Mastodon_api.php
+++ /dev/null
@@ -1,975 +0,0 @@
-
- * @copyright KwangSeon Yun
- * @license https://raw.githubusercontent.com/yks118/Mastodon-api-php/master/LICENSE MIT License
- * @link https://github.com/yks118/Mastodon-api-php
- */
-class Mastodon_api {
- private $mastodon_url = '';
- private $client_id = '';
- private $client_secret = '';
-
- private $token = array();
- private $scopes = array();
-
- public function __construct () {}
-
- public function __destruct () {}
-
- /**
- * _post
- *
- * curl post
- *
- * @param string $url
- * @param array $data
- *
- * @return array $response
- */
- private function _post ($url,$data = array()) {
- $parameters = array();
- $parameters[CURLOPT_POST] = 1;
-
- // set access_token
- if (isset($this->token['access_token'])) {
- $data['access_token'] = $this->token['access_token'];
- }
-
- if (count($data)) {
- $parameters[CURLOPT_POSTFIELDS] = preg_replace('/([(%5B)]{1})[0-9]+([(%5D)]{1})/','$1$2',http_build_query($data));
- }
-
- $url = $this->mastodon_url.$url;
- $response = $this->get_content_curl($url,$parameters);
- return $response;
- }
-
- /**
- * _get
- *
- * @param string $url
- * @param array $data
- *
- * @return array $response
- */
- private function _get ($url,$data = array()) {
- $parameters = array();
-
- // set authorization bearer
- if (isset($this->token['access_token'])) {
- $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
- $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
- }
-
- $url = $this->mastodon_url.$url;
- if (count($data)) {
- $url .= '?' . http_build_query($data);
- }
-
- $response = $this->get_content_curl($url,$parameters);
- return $response;
- }
-
- /**
- * _patch
- *
- * @param string $url
- * @param array $data
- *
- * @return array $parameters
- */
- private function _patch ($url,$data = array()) {
- $parameters = array();
- $parameters[CURLOPT_CUSTOMREQUEST] = 'PATCH';
-
- // set authorization bearer
- if (isset($this->token['access_token'])) {
- $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
- $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
- }
-
- if (count($data)) {
- $parameters[CURLOPT_POSTFIELDS] = json_encode($data);
- }
-
- $url = $this->mastodon_url.$url;
- $response = $this->get_content_curl($url,$parameters);
- return $response;
- }
-
- /**
- * _delete
- *
- * @param string $url
- *
- * @return array $response
- */
- private function _delete ($url) {
- $parameters = array();
- $parameters[CURLOPT_CUSTOMREQUEST] = 'DELETE';
-
- // set authorization bearer
- if (isset($this->token['access_token'])) {
- $authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
- $parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
- }
-
- $url = $this->mastodon_url.$url;
- $response = $this->get_content_curl($url,$parameters);
- return $response;
- }
-
- /**
- * get_content_curl
- *
- * @param string $url
- * @param array $parameters
- *
- * @return array $data
- */
- protected function get_content_curl ($url,$parameters = array()) {
- $data = array();
-
- // set CURLOPT_USERAGENT
- if (!isset($parameters[CURLOPT_USERAGENT])) {
- if (isset($_SERVER['HTTP_USER_AGENT'])) {
- $parameters[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
- } else {
- // default IE11
- $parameters[CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko';
- }
- }
-
- // check curl_init
- if (function_exists('curl_init')) {
- $ch = curl_init();
-
- // url 설정
- curl_setopt($ch,CURLOPT_URL,$url);
-
- foreach ($parameters as $key => $value) {
- curl_setopt($ch,$key,$value);
- }
-
- // https
- if (!isset($parameters[CURLOPT_SSL_VERIFYPEER])) {
- curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
- }
- if (!isset($parameters[CURLOPT_SSLVERSION])) {
- curl_setopt($ch,CURLOPT_SSLVERSION,6);
- }
-
- // no header
- if (!isset($parameters[CURLOPT_HEADER])) {
- curl_setopt($ch,CURLOPT_HEADER,0);
- }
-
- // POST / GET (default : GET)
- if (!isset($parameters[CURLOPT_POST]) && !isset($parameters[CURLOPT_CUSTOMREQUEST])) {
- curl_setopt($ch,CURLOPT_POST,0);
- }
-
- // response get php value
- if (!isset($parameters[CURLOPT_RETURNTRANSFER])) {
- curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
- }
-
- // HTTP2
- if (!isset($parameters[CURLOPT_HTTP_VERSION])) {
- curl_setopt($ch,CURLOPT_HTTP_VERSION,3);
- }
- if (!isset($parameters[CURLINFO_HEADER_OUT])) {
- curl_setopt($ch,CURLINFO_HEADER_OUT,TRUE);
- }
-
- $data['html'] = json_decode(curl_exec($ch),true);
- $data['response'] = curl_getinfo($ch);
-
- curl_close($ch);
- }
-
- return $data;
- }
-
- /**
- * set_url
- *
- * @param string $path
- */
- public function set_url ($path) {
- $this->mastodon_url = $path;
- }
-
- /**
- * set_client
- *
- * @param string $id
- * @param string $secret
- */
- public function set_client ($id,$secret) {
- $this->client_id = $id;
- $this->client_secret = $secret;
- }
-
- /**
- * set_token
- *
- * @param string $token
- * @param string $type
- */
- public function set_token ($token,$type) {
- $this->token['access_token'] = $token;
- $this->token['token_type'] = $type;
- }
-
- /**
- * set_scopes
- *
- * @param array $scopes read / write / follow
- */
- public function set_scopes ($scopes) {
- $this->scopes = $scopes;
- }
-
- /**
- * create_app
- *
- * @param string $client_name
- * @param array $scopes read / write / follow
- * @param string $redirect_uris
- * @param string $website
- *
- * @return array $response
- * int $response['id']
- * string $response['redirect_uri']
- * string $response['client_id']
- * string $response['client_secret']
- */
- public function create_app ($client_name,$scopes = array(),$redirect_uris = '',$website = '') {
- $parameters = array();
-
- if (count($scopes) == 0) {
- if (count($this->scopes) == 0) {
- $scopes = array('read','write','follow');
- } else {
- $scopes = $this->scopes;
- }
- }
-
- $parameters['client_name'] = $client_name;
- $parameters['scopes'] = implode(' ',$scopes);
-
- if (empty($redirect_uris)) {
- $parameters['redirect_uris'] = 'urn:ietf:wg:oauth:2.0:oob';
- } else {
- $parameters['redirect_uris'] = $redirect_uris;
- }
-
- if ($website) {
- $parameters['website'] = $website;
- }
-
- $response = $this->_post('/api/v2/apps',$parameters);
-
- if (isset($response['html']['client_id'])) {
- $this->client_id = $response['html']['client_id'];
- $this->client_secret = $response['html']['client_secret'];
- }
-
- return $response;
- }
-
- /**
- * login
- *
- * @param string $id E-mail Address
- * @param string $password Password
- *
- * @return array $response
- * string $response['access_token']
- * string $response['token_type'] bearer
- * string $response['scope'] read
- * int $response['created_at'] time
- */
- public function login ($id,$password) {
- $parameters = array();
- $parameters['client_id'] = $this->client_id;
- $parameters['client_secret'] = $this->client_secret;
- $parameters['grant_type'] = 'password';
- $parameters['username'] = $id;
- $parameters['password'] = $password;
-
- if (count($this->scopes) == 0) {
- $parameters['scope'] = implode(' ',array('read','write','follow'));
- } else {
- $parameters['scope'] = implode(' ',$this->scopes);
- }
-
- $response = $this->_post('/oauth/token',$parameters);
-
- if (isset($response['html']['access_token'])) {
- $this->token['access_token'] = $response['html']['access_token'];
- $this->token['token_type'] = $response['html']['token_type'];
- }
-
- return $response;
- }
-
- /**
- * accounts
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- * int $response['id']
- * string $response['username']
- * string $response['acct']
- * string $response['display_name'] The name to display in the user's profile
- * bool $response['locked']
- * string $response['created_at']
- * int $response['followers_count']
- * int $response['following_count']
- * int $response['statuses_count']
- * string $response['note'] A new biography for the user
- * string $response['url']
- * string $response['avatar'] A base64 encoded image to display as the user's avatar
- * string $response['avatar_static']
- * string $response['header'] A base64 encoded image to display as the user's header image
- * string $response['header_static']
- */
- public function accounts ($id) {
- $response = $this->_get('/api/v2/accounts/'.$id);
- return $response;
- }
-
- /**
- * accounts_verify_credentials
- *
- * Getting the current user
- *
- * @return array $response
- */
- public function accounts_verify_credentials () {
- $response = $this->_get('/api/v2/accounts/verify_credentials');
- return $response;
- }
-
- /**
- * accounts_update_credentials
- *
- * Updating the current user
- *
- * @param array $parameters
- * string $parameters['display_name'] The name to display in the user's profile
- * string $parameters['note'] A new biography for the user
- * string $parameters['avatar'] A base64 encoded image to display as the user's avatar
- * string $parameters['header'] A base64 encoded image to display as the user's header image
- *
- * @return array $response
- */
- public function accounts_update_credentials ($parameters) {
- $response = $this->_patch('/api/v2/accounts/update_credentials',$parameters);
- return $response;
- }
-
- /**
- * accounts_followers
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_followers ($id) {
- $response = $this->_get('/api/v2/accounts/'.$id.'/followers');
- return $response;
- }
-
- /**
- * accounts_following
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_following ($id) {
- $response = $this->_get('/api/v2/accounts/'.$id.'/following');
- return $response;
- }
-
- /**
- * accounts_statuses
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_statuses ($id) {
- $response = $this->_get('/api/v2/accounts/'.$id.'/statuses');
- return $response;
- }
-
- /**
- * accounts_own_statuses, only own statuses
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_own_statuses ($id) {
- $response = $this->_get('/api/v2/accounts/'.$id.'/statuses?exclude_replies=1');
- $result = [];
- foreach ($response['html'] as $r) {
- if(is_null($r['reblog'])) {
- $result[] = $r;
- }
- }
-
- $response['html'] = $result;
-
- return $response;
- }
-
- /**
- * accounts_follow
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_follow ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/follow');
- return $response;
- }
-
- /**
- * accounts_unfollow
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_unfollow ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/unfollow');
- return $response;
- }
-
- /**
- * accounts_block
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_block ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/block');
- return $response;
- }
-
- /**
- * accounts_unblock
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_unblock ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/unblock');
- return $response;
- }
-
- /**
- * accounts_mute
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_mute ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/mute');
- return $response;
- }
-
- /**
- * accounts_unmute
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function accounts_unmute ($id) {
- $response = $this->_post('/api/v2/accounts/'.$id.'/unmute');
- return $response;
- }
-
- /**
- * accounts_relationships
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param array $parameters
- * int $parameters['id']
- *
- * @return array $response
- * int $response['id']
- * bool $response['following']
- * bool $response['followed_by']
- * bool $response['blocking']
- * bool $response['muting']
- * bool $response['requested']
- */
- public function accounts_relationships ($parameters) {
- $response = $this->_get('/api/v2/accounts/relationships',$parameters);
- return $response;
- }
-
- /**
- * accounts_search
- *
- * @param array $parameters
- * string $parameters['q']
- * int $parameters['limit'] default : 40
- *
- * @return array $response
- */
- public function accounts_search ($parameters) {
- $response = $this->_get('/api/v2/accounts/search',$parameters);
- return $response;
- }
-
- /**
- * blocks
- *
- * @return array $response
- */
- public function blocks () {
- $response = $this->_get('/api/v2/blocks');
- return $response;
- }
-
- /**
- * favourites
- *
- * @return array $response
- */
- public function favourites () {
- $response = $this->_get('/api/v2/favourites');
- return $response;
- }
-
- /**
- * follow_requests
- *
- * @return array $response
- */
- public function follow_requests () {
- $response = $this->_get('/api/v2/follow_requests');
- return $response;
- }
-
- /**
- * follow_requests_authorize
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- *
- * @return array $response
- */
- public function follow_requests_authorize ($id) {
- $response = $this->_post('/api/v2/follow_requests/authorize',array('id'=>$id));
- return $response;
- }
-
- /**
- * follow_requests_reject
- *
- * @see https://your-domain/web/accounts/:id
- *
- * @param int $id
- * @return array $response
- */
- public function follow_requests_reject ($id) {
- $response = $this->_post('/api/v2/follow_requests/reject',array('id'=>$id));
- return $response;
- }
-
- /**
- * follows
- *
- * Following a remote user
- *
- * @param string $uri username@domain of the person you want to follow
- * @return array $response
- */
- public function follows ($uri) {
- $response = $this->_post('/api/v2/follows',array('uri'=>$uri));
- return $response;
- }
-
- /**
- * instance
- *
- * Getting instance information
- *
- * @return array $response
- * string $response['uri']
- * string $response['title']
- * string $response['description']
- * string $response['email']
- */
- public function instance () {
- $response = $this->_get('/api/v2/instance');
- return $response;
- }
-
- /**
- * media
- *
- * Uploading a media attachment
- *
- * @param string $file_path local path / http path
- *
- * @return array $response
- * int $response['id'] ID of the attachment
- * string $response['type'] One of: "image", "video", "gifv"
- * string $response['url'] URL of the locally hosted version of the image
- * string $response['remote_url'] For remote images, the remote URL of the original image
- * string $response['preview_url'] URL of the preview image
- * string $response['text_url'] Shorter URL for the image, for insertion into text (only present on local images)
- */
- public function media ($file_path) {
- $url = $this->mastodon_url.'/api/v2/media';
- $parameters = $data = array();
- $parameters[CURLOPT_HTTPHEADER] = array('Content-Type'=>'multipart/form-data');
- $parameters[CURLOPT_POST] = true;
-
- // set access_token
- if (isset($this->token['access_token'])) {
- $parameters[CURLOPT_POSTFIELDS]['access_token'] = $this->token['access_token'];
- }
-
- if (is_file($file_path)) {
- $mime_type = mime_content_type($file_path);
-
- $cf = curl_file_create($file_path,$mime_type,'file');
- $parameters[CURLOPT_POSTFIELDS]['file'] = $cf;
- }
-
- $response = $this->get_content_curl($url,$parameters);
- return $response;
- }
-
- /**
- * mutes
- *
- * Fetching a user's mutes
- *
- * @return array $response
- */
- public function mutes () {
- $response = $this->_get('/api/v2/mutes');
- return $response;
- }
-
- /**
- * notifications
- *
- * @param int $id
- *
- * @return array $response
- */
- public function notifications ($id = 0) {
- $url = '/api/v2/notifications';
-
- if ($id > 0) {
- $url .= '/'.$id;
- }
-
- $response = $this->_get($url);
- return $response;
- }
-
- /**
- * notifications_clear
- *
- * Clearing notifications
- *
- * @return array $response
- */
- public function notifications_clear () {
- $response = $this->_post('/api/v2/notifications/clear');
- return $response;
- }
-
- /**
- * get_reports
- *
- * Fetching a user's reports
- *
- * @return array $response
- */
- public function get_reports () {
- $response = $this->_get('/api/v2/reports');
- return $response;
- }
-
- /**
- * post_reports
- *
- * Reporting a user
- *
- * @param array $parameters
- * int $parameters['account_id'] The ID of the account to report
- * int $parameters['status_ids'] The IDs of statuses to report (can be an array)
- * string $parameters['comment'] A comment to associate with the report.
- *
- * @return array $response
- */
- public function post_reports ($parameters) {
- $response = $this->_post('/api/v2/reports',$parameters);
- return $response;
- }
-
- /**
- * search
- *
- * Searching for content
- *
- * @param array $parameters
- * string $parameters['q'] The search query
- * string $parameters['resolve'] Whether to resolve non-local accounts
- *
- * @return array $response
- */
- public function search ($parameters) {
- $response = $this->_get('/api/v2/search',$parameters);
- return $response;
- }
-
- /**
- * statuses
- *
- * Fetching a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses ($id) {
- $response = $this->_get('/api/v2/statuses/'.$id);
- return $response;
- }
-
- /**
- * statuses_context
- *
- * Getting status context
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_context ($id) {
- $response = $this->_get('/api/v2/statuses/'.$id.'/context');
- return $response;
- }
-
- /**
- * statuses_card
- *
- * Getting a card associated with a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_card ($id) {
- $response = $this->_get('/api/v2/statuses/'.$id.'/card');
- return $response;
- }
-
- /**
- * statuses_reblogged_by
- *
- * Getting who reblogged a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_reblogged_by ($id) {
- $response = $this->_get('/api/v2/statuses/'.$id.'/reblogged_by');
- return $response;
- }
-
- /**
- * statuses_favourited_by
- *
- * Getting who favourited a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_favourited_by ($id) {
- $response = $this->_get('/api/v2/statuses/'.$id.'/favourited_by');
- return $response;
- }
-
- /**
- * post_statuses
- *
- * @param array $parameters
- * string $parameters['status'] The text of the status
- * int $parameters['in_reply_to_id'] (optional): local ID of the status you want to reply to
- * int $parameters['media_ids'] (optional): array of media IDs to attach to the status (maximum 4)
- * string $parameters['sensitive'] (optional): set this to mark the media of the status as NSFW
- * string $parameters['spoiler_text'] (optional): text to be shown as a warning before the actual content
- * string $parameters['visibility'] (optional): either "direct", "private", "unlisted" or "public"
- *
- * @return array $response
- */
- public function post_statuses ($parameters) {
- $response = $this->_post('/api/v2/statuses',$parameters);
- return $response;
- }
-
- /**
- * delete_statuses
- *
- * Deleting a status
- *
- * @param int $id
- *
- * @return array $response empty
- */
- public function delete_statuses ($id) {
- $response = $this->_delete('/api/v2/statuses/'.$id);
- return $response;
- }
-
- /**
- * statuses_reblog
- *
- * Reblogging a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_reblog ($id) {
- $response = $this->_post('/api/v2/statuses/'.$id.'/reblog');
- return $response;
- }
-
- /**
- * statuses_unreblog
- *
- * Unreblogging a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_unreblog ($id) {
- $response = $this->_post('/api/v2/statuses/'.$id.'/unreblog');
- return $response;
- }
-
- /**
- * statuses_favourite
- *
- * Favouriting a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_favourite ($id) {
- $response = $this->_post('/api/v2/statuses/'.$id.'/favourite');
- return $response;
- }
-
- /**
- * statuses_unfavourite
- *
- * Unfavouriting a status
- *
- * @param int $id
- *
- * @return array $response
- */
- public function statuses_unfavourite ($id) {
- $response = $this->_post('/api/v2/statuses/'.$id.'/unfavourite');
- return $response;
- }
-
- /**
- * timelines_home
- *
- * @return array $response
- */
- public function timelines_home () {
- $response = $this->_get('/api/v2/timelines/home');
- return $response;
- }
-
- /**
- * timelines_public
- *
- * @param array $parameters
- * bool $parameters['local'] Only return statuses originating from this instance
- *
- * @return array $response
- */
- public function timelines_public ($parameters = array()) {
- $response = $this->_get('/api/v2/timelines/public',$parameters);
- return $response;
- }
-
- /**
- * timelines_tag
- *
- * @param string $hashtag
- * @param array $parameters
- * bool $parameters['local'] Only return statuses originating from this instance
- *
- * @return array $response
- */
- public function timelines_tag ($hashtag,$parameters = array()) {
- $response = $this->_get('/api/v2/timelines/tag/'.$hashtag,$parameters);
- return $response;
- }
-}
diff --git a/themes/hugo-mastodon-comments/static/comments/config.sample.php b/themes/hugo-mastodon-comments/static/comments/config.sample.php
index 8cdc8f7..1b48359 100644
--- a/themes/hugo-mastodon-comments/static/comments/config.sample.php
+++ b/themes/hugo-mastodon-comments/static/comments/config.sample.php
@@ -1,7 +1,7 @@
'https://mastodon.social',
- 'user-id' => 549759,
- 'threshold' => 300,
- 'token' => '47598kdjhfgkdg894kejg834joejg43'
+ 'user-id' => 379833,
+ 'search-url' => 'https?://fsfe.org', // please use https?:// as schema
+ 'threshold' => 300
];
diff --git a/themes/hugo-mastodon-comments/static/comments/getcomments.js b/themes/hugo-mastodon-comments/static/comments/getcomments.js
index a7d5576..8df5fe7 100644
--- a/themes/hugo-mastodon-comments/static/comments/getcomments.js
+++ b/themes/hugo-mastodon-comments/static/comments/getcomments.js
@@ -38,11 +38,11 @@ $(document).ready(function() {
}
});
if (parseInt(root) > 0) {
- $("#reference").append("Join the discussion on Mastodon!");
+ $("#reference").append("Join the discussion on Mastodon!");
} else {
$("#comments").empty();
$("#statistics").empty();
- $("#reference").append("Comments are handled by my Mastodon account. Sadly this article wasn't published at Mastodon. Feel free to send me a mail if you want to share your thoughts regarding this topic.");
+ $("#reference").append("Comments are handled by my Mastodon account. Sadly this article wasn't published at Mastodon. Feel free to send me a mail if you want to share your thoughts regarding this topic.");
}
}
diff --git a/themes/hugo-mastodon-comments/static/comments/getcomments.php b/themes/hugo-mastodon-comments/static/comments/getcomments.php
index 2743773..0eca6dc 100644
--- a/themes/hugo-mastodon-comments/static/comments/getcomments.php
+++ b/themes/hugo-mastodon-comments/static/comments/getcomments.php
@@ -1,183 +1,159 @@
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- *
- */
-require_once 'Mastodon_api.php';
-require_once '../../mastodon.feed/config.php';
+require_once 'config.php';
+$instance = $config['mastodon-instance'];
+$uid = $config['user-id'];
+$searchurl = $config['search-url'];
+$search = isset($_GET['search']) ? $_GET['search'] : '';
+/* cache files */
+$dbt = "cache-toots.json";
-class CollectMastodonData {
-
- /** @var \Mastodon_api */
- private $api;
-
- /** @var string url of the mastodon instance */
- private $mastodonUrl = 'https://mastodon.social';
-
- /** @var string token to authenticate at the mastodon instance */
- private $bearerToken;
-
- /** @var int keep cache at least 600 seconds = 10 minutes */
- private $threshold = 600;
-
- /** @var string uid on the mastodon instance */
- private $uid;
-
- /** @var array cached comments from previous searches */
- private $commentCache = [];
-
- private $cacheFile = 'myCommentsCache.json';
-
- public function __construct($config) {
- $this->mastodonUrl = $config['mastodon-instance'];
- $this->bearerToken = $config['token'];
- $this->uid = $config['user-id'];
-
- $this->api = new Mastodon_api();
-
- $this->api->set_url($this->mastodonUrl);
- $this->api->set_token($this->bearerToken, 'bearer');
- }
-
- private function filterComments($descendants, $root, &$result) {
- foreach ($descendants as $d) {
- $result['comments'][$d['id']] = [
- 'author' => [
- 'display_name' => $d['account']['display_name'] ? $d['account']['display_name'] : $d['account']['username'],
- 'avatar' => $d['account']['avatar_static'],
- 'url' => $d['account']['url']
- ],
- 'toot' => $d['content'],
- 'date' => $d['created_at'],
- 'url' => $d['uri'],
- 'reply_to' => $d['in_reply_to_id'],
- 'root' => $root,
- ];
- }
-
- return $result;
- }
-
- private function filterStats($stats) {
- $result = [
- 'reblogs' => (int)$stats['reblogs_count'],
- 'favs' => (int)$stats['favourites_count'],
- 'replies' => (int)$stats['replies_count'],
- 'url' => $stats['url']
- ];
- return $result;
- }
-
- private function filterSearchResults($searchResult) {
- $result = [];
- if (isset($searchResult['html']['statuses'])) {
- foreach ($searchResult['html']['statuses'] as $status) {
- if ($status['in_reply_to_id'] === null) {
- $result[] = $status['id'];
- }
- }
- }
-
- sort($result);
- return $result;
- }
-
- /**
- * find all toots for a given blog post and return the corresponding IDs
- *
- * @param string $search
- * @return array
- */
- public function findToots($search) {
- $result = $this->api->search(['q' => $search]);
- return $this->filterSearchResults($result);
- }
-
- public function getComments($id, &$result) {
- $raw = file_get_contents("https://mastodon.social/api/v1/statuses/$id/context");
- $json = json_decode($raw, true);
- $this->filterComments($json['descendants'], $id, $result);
- }
-
- public function getStatistics($id, &$result) {
- $raw = file_get_contents("https://mastodon.social/api/v1/statuses/$id");
- $json = json_decode($raw, true);
- $newStats = $this->filterStats($json);
- $result['stats']['reblogs'] += $newStats['reblogs'];
- $result['stats']['favs'] += $newStats['favs'];
- $result['stats']['replies'] += $newStats['replies'];
- if (empty($result['stats']['url'])) {
- $result['stats']['url'] = $newStats['url'];
- }
- }
-
- public function storeCollection($id, $comments) {
- $timestamp = time();
- $comments['timestamp'] = $timestamp;
- $this->commentCache[$id] = $comments;
- file_put_contents($this->cacheFile, json_encode($this->commentCache));
- }
-
- public function getCachedCollection($search) {
- if (file_exists($this->cacheFile)) {
- $cachedComments = file_get_contents($this->cacheFile);
- $cachedCommentsArray = json_decode($cachedComments, true);
- if (is_array($cachedCommentsArray)) {
- $this->commentCache = $cachedCommentsArray;
- $currentTimestamp = time();
- if (isset($cachedCommentsArray[$search])) {
- if ((int)$cachedCommentsArray[$search]['timestamp'] + $this->threshold > $currentTimestamp) {
- unset($cachedCommentsArray[$search]['timestamp']);
- return $cachedCommentsArray[$search];
- }
- }
- }
- }
-
- return [];
- }
+/* MISC FUNCTIONS */
+function out($data) {
+ error_log("[getcomments.php] " . print_r($data, TRUE));
}
+/* CACHE FUNCTIONS */
+/* write data to file */
+function write_db($db, $data) {
+ // encode and write file
+ $encoded = json_encode($data, JSON_PRETTY_PRINT);
+ file_put_contents($db, $encoded, LOCK_EX);
+}
+/* access data from file */
+function read_db($db, &$data) {
+ if (! file_exists($db)) {
+ touch($db);
+ }
+ $file = file_get_contents($db, true);
+ $data = json_decode($file, true);
+}
+
+/* TOOT FUNCTIONS */
+function collectToots($instance, $uid, $min_id) {
+ $raw = file_get_contents("$instance/api/v1/accounts/$uid/statuses?exclude_reblogs=true&exclude_replies=true&limit=50&min_id=$min_id");
+ $json = json_decode($raw, true);
+ return($json);
+}
+
+
+/* Collect all the toots */
+$toots = array();
+/* get id of latest cached toot, and set as $min_id */
+read_db($dbt, $toots);
+if (!empty($toots['0']['id'])) {
+ $min_id_cached = $toots['0']['id'];
+ $min_id = $min_id_cached;
+} else {
+ /* if cached toots do not exist, start from oldest toot */
+ $min_id = "0";
+}
+
+
+/* test whether there are new toots available */
+$min_id_new = "1";
+while ($min_id_new !== $min_id) {
+ $min_id_new = $min_id;
+
+ $toots = array_merge(collectToots($instance, $uid, $min_id), $toots);
+ $min_id = $toots['0']['id'];
+}
+
+/* if newer toot has been found, find new URLs */
+// TODO: only look up newly found toots
+if ($min_id !== $min_id_cached) {
+ out("New toots found");
+ $ids = array_column($toots, 'id');
+
+ /* Find out if a toot contains the searched URL */
+ function analyzeToot($instance, $id, $searchurl) {
+ $raw = file_get_contents("$instance/api/v1/statuses/$id");
+ $json = json_decode($raw, true);
+
+ preg_match("|$searchurl.+?(?=\")|i", $json['content'], $matches);
+
+ if(!empty($matches)) {
+ return(strtolower($matches[0]));
+ } else {
+ return("");
+ }
+ }
+
+ $toots = array();
+ foreach ($ids as $id) {
+ $toots[] = array('id' => $id, 'url' => analyzeToot($instance, $id, $searchurl));
+ }
+
+ write_db($dbt, $toots);
+} else {
+ out("No new toots found");
+}
+
+/* check if URL from $search exists in $toots */
+// if multiple exist, take the oldest one (highest array position)
+$id = array_keys(array_column($toots, 'url'), strtolower($search));
+$id = $toots[end($id)]['id'];
+// TODO: graceful exit if no toot exists
+
+
+$id = "102955148581768112"; // TODO test
+/* Extract comments and stats from toot */
$result = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]];
-$search = isset($_GET['search']) ? $_GET['search'] : '';
-$collector = new CollectMastodonData($config);
-$ids = [];
-if (!empty($search)) {
- $oldCollection = $collector->getCachedCollection($search);
- if (empty($oldCollection)) {
- $ids = $collector->findToots($search);
- $result['stats']['root'] = isset($ids[0]) ? $ids[0] : 0;
- foreach ($ids as $id) {
- // get comments
- $newComments = $collector->getComments($id, $result);
- // get statistics (likes, replies, boosts,...)
- $collector->getStatistics($id, $result);
- // FIXME: At the moment the API doesn't return the correct replies count so I count it manually
- $result['stats']['replies'] = count($result['comments']);
- }
- $collector->storeCollection($search, $result);
- } else {
- $result = $oldCollection;
- }
+function filterComments($descendants, $root, &$result) {
+ foreach ($descendants as $d) {
+ $result['comments'][$d['id']] = [
+ 'author' => [
+ 'display_name' => $d['account']['display_name'] ? $d['account']['display_name'] : $d['account']['username'],
+ 'avatar' => $d['account']['avatar_static'],
+ 'url' => $d['account']['url']
+ ],
+ 'toot' => $d['content'],
+ 'date' => $d['created_at'],
+ 'url' => $d['uri'],
+ 'reply_to' => $d['in_reply_to_id'],
+ 'root' => $root,
+ ];
+ }
+ return $result;
}
+function tootContext($instance, $id, &$result) {
+ $raw = file_get_contents("$instance/api/v1/statuses/$id/context");
+ $json = json_decode($raw, true);
+ filterComments($json['descendants'], $id, $result);
+}
+
+function filterStats($stats) {
+ $result = [
+ 'reblogs' => (int)$stats['reblogs_count'],
+ 'favs' => (int)$stats['favourites_count'],
+ 'replies' => (int)$stats['replies_count'],
+ 'url' => $stats['url']
+ ];
+ return $result;
+}
+
+function tootStats($instance, $id, &$result) {
+ out("Checking ID $id");
+ $raw = file_get_contents("$instance/api/v1/statuses/$id");
+ $json = json_decode($raw, true);
+ $newStats = filterStats($json);
+ $result['stats']['reblogs'] += $newStats['reblogs'];
+ $result['stats']['favs'] += $newStats['favs'];
+ $result['stats']['replies'] += $newStats['replies'];
+ if (empty($result['stats']['url'])) {
+ $result['stats']['url'] = $newStats['url'];
+ }
+}
+
+// FIXME: At the moment the API doesn't return the correct replies count so I count it manually
+$result['stats']['replies'] = count($result['comments']);
+$result['stats']['root'] = $id;
+tootContext($instance, $id, $result);
+tootStats($instance, $id, $result);
+
+
// headers for not caching the results
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
@@ -185,5 +161,6 @@ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
// headers to tell that result is JSON
header('Content-type: application/json');
-// send the result now
echo json_encode($result);
+
+?>
diff --git a/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css b/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css
index 615ad72..0da2180 100644
--- a/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css
+++ b/themes/hugo-mastodon-comments/static/comments/mastodon-comments.css
@@ -1,3 +1,8 @@
+.comments-container {
+ text-align: left;
+ padding-bottom: 15px;
+}
+
.comments-container .comment .avatar {
float: left;
width: 50px;
@@ -5,6 +10,7 @@
margin-left: 16px;
margin-right: 16px;
border-radius: 50%;
+ padding-top: 0;
}
.comments-container #reference {