[PatreonBridge] Add new bridge (#1254)
* [PatreonBridge] Add new bridge * [PatreonBridge] Add UID to articles Patreon changes post URLs when the post title is updated, so set a UID based on the post ID instead.
This commit is contained in:
parent
25548b6757
commit
abb74f056c
1 changed files with 203 additions and 0 deletions
203
bridges/PatreonBridge.php
Normal file
203
bridges/PatreonBridge.php
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
class PatreonBridge extends BridgeAbstract {
|
||||
const NAME = 'Patreon Bridge';
|
||||
const URI = 'https://www.patreon.com/';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = 'Returns posts by creators on Patreon';
|
||||
const MAINTAINER = 'Roliga';
|
||||
const PARAMETERS = array( array(
|
||||
'creator' => array(
|
||||
'name' => 'Creator',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Creator name as seen in their page URL'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOMCached($this->getURI(), 86400)
|
||||
or returnServerError('Failed to load creator page at ' . $this->getURI());
|
||||
$regex = '#/api/campaigns/([0-9]+)#';
|
||||
if(preg_match($regex, $html->save(), $matches) > 0) {
|
||||
$campaign_id = $matches[1];
|
||||
} else {
|
||||
returnServerError('Could not find campaign ID');
|
||||
}
|
||||
|
||||
$query = array(
|
||||
'include' => implode(',', array(
|
||||
'user',
|
||||
'attachments',
|
||||
'user_defined_tags',
|
||||
//'campaign',
|
||||
//'poll.choices',
|
||||
//'poll.current_user_responses.user',
|
||||
//'poll.current_user_responses.choice',
|
||||
//'poll.current_user_responses.poll',
|
||||
//'access_rules.tier.null',
|
||||
//'images.null',
|
||||
//'audio.null'
|
||||
)),
|
||||
'fields' => array(
|
||||
'post' => implode(',', array(
|
||||
//'change_visibility_at',
|
||||
//'comment_count',
|
||||
'content',
|
||||
//'current_user_can_delete',
|
||||
//'current_user_can_view',
|
||||
//'current_user_has_liked',
|
||||
//'embed',
|
||||
'image',
|
||||
//'is_paid',
|
||||
//'like_count',
|
||||
//'min_cents_pledged_to_view',
|
||||
//'patreon_url',
|
||||
//'patron_count',
|
||||
//'pledge_url',
|
||||
//'post_file',
|
||||
//'post_metadata',
|
||||
//'post_type',
|
||||
'published_at',
|
||||
'teaser_text',
|
||||
//'thumbnail_url',
|
||||
'title',
|
||||
//'upgrade_url',
|
||||
'url',
|
||||
//'was_posted_by_campaign_owner'
|
||||
)),
|
||||
'user' => implode(',', array(
|
||||
//'image_url',
|
||||
'full_name',
|
||||
//'url'
|
||||
))
|
||||
),
|
||||
'filter' => array(
|
||||
'contains_exclusive_posts' => true,
|
||||
'is_draft' => false,
|
||||
'campaign_id' => $campaign_id
|
||||
),
|
||||
'sort' => '-published_at'
|
||||
);
|
||||
$posts = $this->apiGet('posts', $query);
|
||||
|
||||
foreach($posts->data as $post) {
|
||||
$item = array(
|
||||
'uri' => $post->attributes->url,
|
||||
'title' => $post->attributes->title,
|
||||
'timestamp' => $post->attributes->published_at,
|
||||
'content' => '',
|
||||
'uid' => 'patreon.com/' . $post->id
|
||||
);
|
||||
|
||||
$user = $this->findInclude($posts,
|
||||
'user',
|
||||
$post->relationships->user->data->id);
|
||||
$item['author'] = $user->full_name;
|
||||
|
||||
if(isset($post->attributes->image))
|
||||
$item['content'] .= '<p><a href="'
|
||||
. $post->attributes->url
|
||||
. '"><img src="'
|
||||
. $post->attributes->image->thumb_url
|
||||
. '" /></a></p>';
|
||||
|
||||
if(isset($post->attributes->content)) {
|
||||
$item['content'] .= $post->attributes->content;
|
||||
} elseif (isset($post->attributes->teaser_text)) {
|
||||
$item['content'] .= '<p>'
|
||||
. $post->attributes->teaser_text
|
||||
. '</p>';
|
||||
}
|
||||
|
||||
if(isset($post->relationships->user_defined_tags)) {
|
||||
$item['categories'] = array();
|
||||
foreach($post->relationships->user_defined_tags->data as $tag) {
|
||||
$attrs = $this->findInclude($posts, 'post_tag', $tag->id);
|
||||
$item['categories'][] = $attrs->value;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($post->relationships->attachments)) {
|
||||
$item['enclosures'] = array();
|
||||
foreach($post->relationships->attachments->data as $attachment) {
|
||||
$attrs = $this->findInclude($posts, 'attachment', $attachment->id);
|
||||
$item['enclosures'][] = $attrs->url;
|
||||
}
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches the "included" array in an API response and returns attributes
|
||||
* for the first match.
|
||||
*/
|
||||
private function findInclude($data, $type, $id) {
|
||||
foreach($data->included as $include)
|
||||
if($include->type === $type && $include->id === $id)
|
||||
return $include->attributes;
|
||||
}
|
||||
|
||||
private function apiGet($endpoint, $query_data = array()) {
|
||||
$query_data['json-api-version'] = 1.0;
|
||||
$query_data['json-api-use-default-includes'] = 0;
|
||||
|
||||
$url = 'https://www.patreon.com/api/'
|
||||
. $endpoint
|
||||
. '?'
|
||||
. http_build_query($query_data);
|
||||
|
||||
/*
|
||||
* Accept-Language header and the CURL cipher list are for bypassing the
|
||||
* Cloudflare anti-bot protection on the Patreon API. If this ever breaks,
|
||||
* here are some other project that also deal with this:
|
||||
* https://github.com/mikf/gallery-dl/issues/342
|
||||
* https://github.com/daemionfox/patreon-feed/issues/7
|
||||
* https://www.patreondevelopers.com/t/api-returning-cloudflare-challenge/2025
|
||||
* https://github.com/splitbrain/patreon-rss/issues/4
|
||||
*/
|
||||
$header = array(
|
||||
'Accept-Language: en-US',
|
||||
'Content-Type: application/json'
|
||||
);
|
||||
$opts = array(
|
||||
CURLOPT_SSL_CIPHER_LIST => implode(':', array(
|
||||
'DEFAULT',
|
||||
'!DHE-RSA-CHACHA20-POLY1305'
|
||||
))
|
||||
);
|
||||
|
||||
$data = json_decode(getContents($url, $header, $opts))
|
||||
or returnServerError('API request to "' . $url . '" failed.');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('creator')))
|
||||
return $this->getInput('creator') . ' posts';
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('creator')))
|
||||
return self::URI . $this->getInput('creator');
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function detectParameters($url){
|
||||
$params = array();
|
||||
|
||||
// Matches e.g. https://www.patreon.com/SomeCreator
|
||||
$regex = '/^(https?:\/\/)?(www\.)?patreon\.com\/([^\/&?\n]+)/';
|
||||
if(preg_match($regex, $url, $matches) > 0) {
|
||||
$params['creator'] = urldecode($matches[3]);
|
||||
return $params;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue