Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- //Text to Bluesky (with link card) sample 2025-06
- //MH+ presents, visit my blog => https://sl-memo.blogspot.com/
- date_default_timezone_set('Asia/Tokyo');
- $UAstring = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0";
- //入力データ
- $readfile = "text_data.txt";
- //$readdata = explode("\n", file_get_contents($readfile));
- //テスト用なので固定の配列で記述
- $readdata = array(
- '001<->IMG - 3<->https://www.flickr.com/photos/153589246@N07/37182374834/<->https://live.staticflickr.com/4459/37182374834_a89ca42e10_c.jpg'
- ,'002<->Baby Anythings are Cute<->https://www.flickr.com/photos/dennissylvesterhurd/52852294515/<->https://live.staticflickr.com/65535/52852294515_b00fb1e17d_c.jpg'
- ,'003<->Labradoodle<->https://www.flickr.com/photos/195591092@N07/52064576115/<->https://live.staticflickr.com/65535/52064576115_636e0487bf_c.jpg'
- ,'004<->Day with Monty 1<->https://www.flickr.com/photos/ianlivesey/49847245082/<->https://live.staticflickr.com/65535/49847245082_41ca62b972_c.jpg'
- );
- $counter = 0;
- //Bluesky接続 (Json Web Token (JWT) 取得)
- $handle = "**********************"; //あなたのBluesky ID (username.bsky.social など)
- $password = "**********************"; //あなたのBluesky パスワード
- $jwt = NULL;
- $connect_FLG = false;
- $logfile = "text_test.log";
- $log_FLG = false;
- //Main処理
- //各行毎で処理する
- foreach($readdata as $lines) {
- $items = explode("<->", $lines);// 0=番号, 1=タイトル, 2=URL, 3=imageURL
- //画像URLの無いものは破棄
- if(!(isset($items[3]))) continue;
- if(!$connect_FLG){
- $connect_FLG = true;
- // Json Web Token (JWT) 取得
- $jwt = login($handle, $password);
- }
- //-----------------------------------------------------------------------------------------------
- //Blusky 投稿
- $title= (string)$items[1];
- $link = (string)$items[2];
- $image= (string)$items[3];
- $text = $title . " #Flickr #PublicDomain \n" . $link;
- $facets = [];
- //この辺の facets でのタグ付けやLink付けを丸投げでやってくれるライブラリーもあるらしい
- //Linkを付ける
- $linkStart = strpos($text, $link);
- $linkEnd = $linkStart + strlen($link);
- $facets[] = [
- 'index' => [
- 'byteStart' => $linkStart,
- 'byteEnd' => $linkEnd
- ],
- 'features' => [
- [
- '$type' => 'app.bsky.richtext.facet#link',
- 'uri' => $link
- ]
- ]
- ];
- //HashTagを付ける
- $tagstring = "#Flickr";// # を含む
- $linkStart = strpos($text, $tagstring);
- $linkEnd = $linkStart + strlen($tagstring);
- $facets[] = [
- 'index' => [
- 'byteStart' => $linkStart,
- 'byteEnd' => $linkEnd
- ],
- 'features' => [
- [
- '$type' => 'app.bsky.richtext.facet#tag',
- 'tag' => "Flickr" // # を含まない
- ]
- ]
- ];
- $tagstring = "#PublicDomain";// # を含む
- $linkStart = strpos($text, $tagstring);
- $linkEnd = $linkStart + strlen($tagstring);
- $facets[] = [
- 'index' => [
- 'byteStart' => $linkStart,
- 'byteEnd' => $linkEnd
- ],
- 'features' => [
- [
- '$type' => 'app.bsky.richtext.facet#tag',
- 'tag' => "PublicDomain" // # を含まない
- ]
- ]
- ];
- $record = [
- '$type' => "app.bsky.feed.post",
- 'text' => $text,
- 'createdAt' => (new DateTime())->format("c"),
- 'facets' => $facets,
- ];
- //画像データ取得とUpload
- $imageUri = uploadImage($jwt, $image);
- $record['embed'] = [
- '$type' => 'app.bsky.embed.external',
- 'external'=> [
- 'uri' => $link, //リンクカードのURL
- 'title' => $title,
- 'description' => 'Blog記事用のネタ投稿です。descriptionは省略可。titleは省略するとurlになるよ',
- 'thumb' => $imageUri,
- ],
- ];
- $response = post_w_link($handle, $jwt, $record);
- file_put_contents($logfile,print_r($response,true),$log_FLG);
- if(!$log_FLG) $log_FLG = FILE_APPEND;
- if(isset($response['validationStatus'])){
- if($response['validationStatus'] == 'valid'){
- //投稿成功
- $counter++;
- }
- }
- //-----------------------------------------------------------------------------------------------
- usleep(100000 * 3);//0.1秒 x N停止 (sleep 1秒 = usleep 1000000)
- }
- echo "total : " . (string)$counter ." items post\n";
- /////////////////////////////////////////////////////////////////
- function login($handle, $password)
- {
- $ch = curl_init("https://bsky.social/xrpc/com.atproto.server.createSession");
- curl_setopt_array($ch, [
- CURLOPT_CONNECTTIMEOUT => 10,
- CURLOPT_SSL_VERIFYPEER => false,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_MAXREDIRS => 1000,
- CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_POST => true,
- CURLOPT_USERAGENT => $GLOBALS['UAstring'],
- CURLOPT_HTTPHEADER => [
- "Content-Type: application/json",
- ],
- CURLOPT_POSTFIELDS => json_encode([
- "identifier" => $handle,
- "password" => $password,
- ]),
- ]);
- $response = curl_exec($ch);
- if(curl_error($ch)){
- echo "login error : " . curl_error($ch) . "\n";
- die();
- }
- curl_close($ch);
- $responseJson = json_decode($response, true);
- if(isset($responseJson["accessJwt"])){
- return $responseJson["accessJwt"];
- }else{
- print_r($responseJson);
- }
- }
- function post_w_link($handle, $jwt, $record)
- {
- $ch = curl_init("https://bsky.social/xrpc/com.atproto.repo.createRecord");
- curl_setopt_array($ch, [
- CURLOPT_CONNECTTIMEOUT => 10,
- CURLOPT_SSL_VERIFYPEER => false,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_MAXREDIRS => 1000,
- CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_POST => true,
- CURLOPT_USERAGENT => $GLOBALS['UAstring'],
- CURLOPT_HTTPHEADER => [
- "Content-Type: application/json",
- "Authorization: Bearer {$jwt}",
- ],
- CURLOPT_POSTFIELDS => json_encode([
- "repo" => $handle,
- "collection" => "app.bsky.feed.post",
- "record" => $record,
- ]),
- ]);
- $response = curl_exec($ch);
- if(curl_error($ch)){
- echo "post error : " . curl_error($ch) . "\n";
- die();
- }
- curl_close($ch);
- $responseJson = json_decode($response, true);
- return $responseJson;
- }
- function uploadImage($jwt, $imagePath)
- {
- $imageData = file_get_contents($imagePath);
- // $mime = mime_content_type($imagePath);
- //Flickr は形式固定なのでローカル保存しない
- //他サイト等て混在する場合は一時的にローカル環境に出力してmime_content_typeで判別
- $mime = 'image/jpeg';
- $ch = curl_init("https://bsky.social/xrpc/com.atproto.repo.uploadBlob");
- curl_setopt_array($ch, [
- CURLOPT_CONNECTTIMEOUT => 10,
- CURLOPT_SSL_VERIFYPEER => false,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_MAXREDIRS => 1000,
- CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
- CURLOPT_POST => true,
- CURLOPT_USERAGENT => $GLOBALS['UAstring'],
- CURLOPT_HTTPHEADER => [
- "Content-Type: $mime",
- "Authorization: Bearer {$jwt}",
- ],
- CURLOPT_POSTFIELDS => $imageData,
- ]);
- $response = curl_exec($ch);
- if(curl_error($ch)){
- echo "upload error : " . curl_error($ch) . "\n";
- die();
- }
- curl_close($ch);
- $responseJson = json_decode($response, true);
- return $responseJson['blob'] ?? null; //PHP 7.x 以降要
- /*
- 3項演算の亜種
- $x ?? $y; は
- isset($x) ? $x : $y; と同じ効果です(PHP 7.x以上)
- */
- }
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement