我在我的部落格上有很多長青內容。本教程將解釋我如何自動化在Twitter上重複使用這些內容的過程。

我定期在我的部落格上發表長青內容。所謂長青指的是內容不會關於新聞或最近的事件,而是即使今天有效,一年後,甚至五年後,如果我繼續進行更新以防止信息過時,它仍然有效。

每次我撰寫新的部落格文章時,我都會在Twitter上分享它,如果我的少數幾位絕妙的追隨者(👋)沒有在那裡看到它,他們可能永遠不會再次看到它,我認為這對我來說是一種不公平(因為我在撰寫該部落格文章時花了很多時間) ,對可能通過該文章學到新知識的人也是一種不公平。

我有時會不時分享一篇舊文章,但這是一個手動過程。我必須記得這樣做,而且我還必須記錄我已經分享過的內容,以避免再次發佈相同的內容。

因此,我想在這個問題周圍創建一個小小的自動化,以在我睡覺的時候每天發佈2篇舊文章

我知道有一些服務可以做到這一點,但是-嘿-我們是開發人員,開發人員會建立自己的工具 😄

我想創建一個應用程序,從列表中查找我要重複使用的帖子,當我調用特定的URL時,它會分享一篇隨機的帖子,總是選擇一篇不久前分享的帖子。

應用程序將基於Node.js,托管在Glitch上。我經常在教程中使用Glitch來進行代碼示例,它非常好用!

你不僅僅可以創建小型演示,還可以創建一個完整的Node.js應用程序,這對我的需求來說非常合適。儘管應用程序在幾個小時的不活動後關閉,但是一個HTTP請求就可以喚醒它。

最後一個謎題是決定在哪裡托管數據。我想要一個容易訪問的服務,不需要繁瑣的權限和授權設置,所以我選擇了Airtable。

在Airtable上托管數據

Airtable是一個類似於電子表格和數據庫的混合體。您可以非常輕松地添加數據,也可以通過API很容易地導出數據。

我創建了一個簡單的底部來保存帖子表:

它有以下列:

  • 標題:帖子標題
  • 鏈接:帖子鏈接
  • 已分享:如果該帖子最近已經分享過了
  • 禁用:如果選中,則該帖子將不會被 分享。有用的"暫停"內容
  • 描述:可選的文字,將在標題之後,在鏈接之前分享在Twitter上

我在表中填充了一些帖子。您可以

我將使用這個表作為數據源,並使用Node.js API進行訪問。Airtable.js是官方的JavaScript庫。

Airtable的一個很酷的功能是API文檔是動態的,並且根據您的表的鍵和ID進行個性化,因此您可以直接將代碼放在應用程序中。 它還更進一步,提供您使用的確切字段以及實時內容:

這本身就很神奇,我希望更多的服務在他們的API文檔中也做這樣的好事。

現在,進入Glitch!

在Glitch上創建Node.js應用程序

我在Glitch上構建的Node.js應用程序需要與Airtable和Twitter通信。

這是完整的應用程序:https://glitch.com/edit/#!/flavio-repurpose-old-posts-twitter

Glitch提供了一個很好的功能,允許您在共享項目時將密鑰和參數保密,方法是將它們放在.env文件中。

我設定了Airtable訪問的密鑰:

  • AIRTABLE_API_KEY
  • AIRTABLE_BASE_ID
  • AIRTABLE_BASE_NAME
  • AIRTABLE_VIEW_NAME

以及Twitter的鍵:

  • TWITTER_CONSUMER_KEY
  • TWITTER_CONSUMER_SECRET
  • TWITTER_ACCESS_TOKEN
  • TWITTER_ACCESS_TOKEN_SECRET

這些Twitter參數是由Twitter Apps面板提供的。創建一個應用程序以獲取消費者密鑰和秘密,並通過單擊生成一個個人訪問令牌。

應用程序以此構建。在Node.js代碼中,通過process.env可以訪問.env值。

依賴項

應用程序使用

我使用方便的添加套件功能將它們添加到Glitch中,該功能在打開package.json文件後可用。

初始化Airtable

讓我們開始:

const base = require('airtable').base(process.env.AIRTABLE_BASE_ID)

通過在基底上調用select()方法,Airtable返回一個查詢對象。

查詢對象可以用於提取記錄。它以每次100行的塊返回內容。

我們需要通過這些進行分頁並存儲所有帖子,以防列表超過100項。

分頁查詢該表的記錄

我們使用eachPage方法進行分頁查詢,它接受兩個函數。一個在每次迭代時執行,另一個在完成內容提取時執行,我們擁有所有記錄:

const repurposeOldPost = () => {
  posts = []
  base(process.env.AIRTABLE_BASE_NAME)
  .select({
    view: process.env.AIRTABLE_VIEW_NAME,
  })
  .eachPage(processPage, processPosts)
}

processPage()處理單個“頁面”的結果,最多 100條記錄。它首先過濾列表以排除標題值為空的項(以跳過空行)和禁用列設置為true的項。

然後,它將值映射到一個新數組中,該數組僅包含我們需要的屬性(idtitlelinkshareddescription),並將結果分配給partialPosts

它將該數組與當前存儲所有項目的posts變量合併,在獲取下100項以處理。

const processPage = (records, fetchNextPage) => {
  const partialPosts = records
  .filter((record) => {
  if (record.get('Title') && record.get('Disabled') !== true) return true
  })
  .map((record) => {
  return {
  id: record.id,
  title: record.get('Title'),
  link: record.get('Link'),
  shared: record.get('Shared') || false,
  description: record.get('Description'),
  }
  })

  posts = [...posts, ...partialPosts]

  fetchNextPage()
}

當此過程完成時,eachPage()調用processPosts()

處理所有帖子

這是分析所有帖子列表並處理推文的地方:

const processPosts = (err) => {
  if (err) {
  console.error(err)
  return
  }

  let post
  const notShared = posts.filter((post) => post.shared === false)

  if (notShared.length === 0) {
  //already shared all posts, clear them and just get the first
  post = posts[0]
  clearSharedStateForAllPosts(posts)
  } else {
  post = notShared[0]
  }

  if (canTweet(lastTweetTimestamp)) {
  updateLastTweetTimestamp()
  tweet(post)
  setAsSharedOnAirtable(post)
  } else {
  console.error('Tweeting too much')
  }
}

首先,我找到最近未共享的帖子列表。我想從這個列表中選擇一篇帖子,這樣在重新共享一篇帖子之前,必須共享其他所有帖子。這很重要,因為我想對材料進行恰當的輪換。

我選擇此列表中的第一個。如果所有帖子已被分享,我會清除共享列,並從所有帖子列表中選擇第一個帖子。

一旦我有了一篇帖子,我檢查是否可以發送推文-我在canTweet()函數中設置了60分鐘的檢查時間間隔,以防止誤觸多次調用URL而不察覺地洪水般的推文。

let lastTweetTimestamp = 0

const canTweet = (lastTweetTimestamp) => {
  if (lastTweetTimestamp === 0) {
  return true
  }

  const currentTimestamp = Math.floor(Date.now() / 1000)
  if (currentTimestamp - lastTweetTimestamp > 60 * 60) {
  return true
  }

  return false
}

如果我可以推文,我將更新全局時間戳值,以便下一次檢查基於此上次推文時間。

我用tweet(post)發推文,這在Twit庫的幫助下非常簡單:

const Twit = require('twit')

const twitter = new Twit({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token: process.env.TWITTER_ACCESS_TOKEN,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
})

const tweet = (post) => {
  let status = `${post.title} ${post.link}`
  if (post.description) {
  status = `${post.title} ${post.description} ${post.link}`
  }

  twitter.post('statuses/update', { status: status }, (err, data, response) => {
  //console.log(data) //inspect the Twitter response
  })
}

推文內容是${post.title} ${post.link},除非描述字段中有其他內容,否則為${post.title} ${post.description} ${post.link}

該字段是多行字段,因此我可以在其中使用表情符號和格式。

進入Express

我們現在需要一種方式來公開所有這些功能!Express非常適合這個。我將其設置為侦聽GET請求在/repurpose-old-post上。

GET對於測試而言更方便。為了防止任何人都能夠發送推文,例如通過訪問我的Glitch(在我的情况下是公開的,以示示範,但也可以是私有的),我設置了一個名為secret的URL查詢參數,在.env文件中設置,因此只對我可見:

SECRET_URL_PARAMETER=something
const express = require('express')
const app = express()

app.get('/repurpose-old-post', (request, response) => {
  if (request.query.secret === process.env.SECRET_URL_PARAMETER) {
  repurposeOldPost()
  response.send('Tweet sent')
  } else {
  console.log('Wrong secret parameter')
  }
})

app.listen(process.env.PORT)

一切都正在運行!

這太完美了!現在,您可以通過點擊Show按鈕打開您的glitch前端,並使用您設置的私密URL調用URL。

如果您正確配置了Twitter和Airtable的憑據,並在Airtable基礎上放置了內容,它應該會幫您發推文:

自動發佈使用IFTTT

IFTTT(即IF這就是那)是一個了不起的工具,可以幫助您自動執行任務。

我設置它在一天的特定時間調用我的URL:

創建一個自動化非常容易,點擊“New Applet”:

點擊this並出現服務列表:

點擊Date & Time服務:

選擇“Every day at”:

選擇一天的時間。現在第一部分已經完成。點擊that

選擇一個操作服務。選擇Webhook服務:

填寫發送到Glitch的請求的詳細信息(或者您想要的任何URL):

最後,點擊create action,然後點擊finish

就是這樣!我們現在可以坐下來觀看我們的Twitter自動駕駛🤖,但別忘記Twitter不僅僅用於推出您的“內容”。它是用於交流的,所以如果您想要增加關注者,請確保不要陷入只推送內容的陷阱,而是與之互動並在推文中找到平衡。