這篇文章一開始釋出在我的部落格,其中的上傳圖片的解決方案,我是越用越覺得好用,分享給大家。
自從寫部落格以來,一直有上傳圖片的需求,一開始用第三方圖床,例如微博等等,其缺點是圖片不屬於自己,某一天可能就無法訪問了。後來也折騰過騰訊、阿里的物件儲存。直到後來發現可以把檔案存在 github 上,再配合 jsdelivr 的 CDN,在國內訪問速度也挺快。
至於上傳圖片的工具,用過 iPic、uPic、picGo,其中 iPic 是付費的,他們的好處是支援不同的圖床、配置方便、不需要折騰。
本著能少安裝軟體就不安裝的原則,我寫了一個 Python 指令碼,配合系統自帶的 Automator ,實現了把資料夾裡的檔案(包括圖片)、微信群裡的圖片或者剪下板的圖片上傳到 github,如果你開了”接力”功能,你也可以上傳在手機裡複製圖片。
效果
這裡本來是一段演示視訊,但是本站無法顯示,如果有需要,可以去原地址看。
Python 指令碼
在電腦上新建一個 Python 檔案,例如upload-file.py
,把下面的內容複製進去。
import io
import os
import re
import json
import time
import base64
import requests
import subprocess
from urllib import parse
# Pillow
from PIL import Image, ImageGrab
# PyObjC
from AppKit import NSPasteboard, NSURLPboardType
# 從剪下板獲取完整的檔案路徑
def getPath():
# https://developer.apple.com/documentation/appkit/nspasteboard/pasteboardtype
pb = NSPasteboard.generalPasteboard()
url = pb.stringForType_(NSURLPboardType)
if url is None:
return None
else:
plistBytes = url.encode("utf-8")
pathByte = re.findall(rb'<string>file://(.+?)</string>', plistBytes)[0]
pathUTF8 = pathByte.decode('utf-8')
return parse.unquote(pathUTF8)
# 把資料推送到 github
def push(base64, filename):
url = "https://api.github.com/repos/[yourGithubName]/[yourRepository]/contents/" + filename
headers = {"Authorization": "token [yourToken]"}
data = json.dumps({
"message": "auto commit",
"committer": {
"name": "[yourName]",
"email": "[yourEmail]"
},
"content": base64
})
response = requests.put(url=url, data=data, headers=headers)
return response
# 從檔案路徑得到檔案字尾
def getExtension(path):
return os.path.splitext(path)[1]
# 用 Base64 對給定的 Bytes 進行編碼
def bytesToBase64(data):
return base64.b64encode(data).decode('utf-8')
# 拼接檔名
def getFilename(extension):
return time.strftime("%Y%m%d%H%M%S", time.localtime()) + extension
# 處理 github 返回的響應
def handleResponse(response, filename, extension):
if response.status_code == 201:
url = buildUrl(filename, extension)
copyToClipboard(url)
icon = "✅"
else:
icon = "❌"
return icon + " " + response.reason
# 處理本地檔案
def handleLocalFile(path):
with open(path, 'rb') as f:
extension = getExtension(path)
base64 = bytesToBase64(f.read())
filename = getFilename(extension)
response = push(base64, filename)
return handleResponse(response, filename, extension)
# 處理剪下板的檔案,與本地檔案不同的是,剪下板的檔案好像是在記憶體中,它並沒有一個檔案路徑(有待研究)
def handleClipboard():
image = ImageGrab.grabclipboard()
if isinstance(image, Image.Image):
buffer = io.BytesIO()
imageFormat = "png"
extension = "." + imageFormat
image.save(buffer, imageFormat)
base64 = bytesToBase64(buffer.getvalue())
filename = getFilename(extension)
response = push(base64, filename)
return handleResponse(response, filename, extension)
else:
return "❌ 剪下板的內容不是圖片"
# 把給定的字串複製到剪下板
def copyToClipboard(data):
p = subprocess.Popen(['pbcopy'], stdin=subprocess.PIPE)
p.stdin.write(data.encode("utf-8"))
p.stdin.close()
p.communicate()
# 判斷是否是圖片
def isImage(extension):
return extension in [".png", ".jpeg", ".gif", "jpg"]
# 按照 jsdelivr 的規則構建 url
def buildUrl(filename, extension):
url = "https://cdn.jsdelivr.net/gh/[yourGithubName]/[yourRepository]@[theBranch]/" + filename
if isImage(extension):
url = markdown(url)
return url
# 按照 markdown 語法拼接 url
def markdown(url):
return "![](" + url + ")"
if __name__ == '__main__':
path = getPath()
if path is None:
toast = handleClipboard()
else:
toast = handleLocalFile(path)
print(toast)
配置項
這個 Python 指令碼其中的一些個人資訊沒有做成可配置的,需要手動改一下,改的時候把中括號去掉。
- [yourGithubName]:github 的名字
- [yourRepository]:儲存檔案的倉庫名
- [yourToken]:在這裡生成的 token,需要具有訪問倉庫的許可權。
- [yourGithubEmail]:任意一個郵箱,通常填寫的是提交人的郵箱。
- [theBranch]:想要把檔案儲存到哪個分支,如果沒有特殊需求,通常是 master 或者 main。
安裝 python 依賴
執行pip3 install pyobjc
安裝 pyobjc
執行pip3 install pip install Pillow
安裝 Pillow
- pyobjc:一個 Python 和 Object-C 之間的橋樑,使得我們可以在 Python 中使用 AppKit 提供的功能,例如訪問剪下板。
- Pillow:一個 Python 的影像處理庫
這兩個庫的功能可能重複了,pyobjc 可能也具備處理影像的功能,但是我沒有深入研究。
在命令列執行指令碼上傳檔案
配置好之後,這個指令碼就可以使用了。使用截圖工具截一張圖片,然後在終端裡執行python3 /path-to-file/upload-file.py
,如果沒出錯,終端會返回提示資訊。或者也可以在訪達中複製一個已經存在的檔案,然後執行指令碼。
如果檔案很大,上傳花費的時間可能很久。另外由於 jsdelivr 的限制,好像是超過 20M 的檔案,就不可以訪問了。關於這一點,暫時沒有好辦法,只能儘可能的把圖片或者檔案控制在 20M 之內。
搭配 Automator 使用
上面的指令碼已經可以使用了,但是每次跑命令列依然很麻煩,蘋果電腦提供了一個叫做 Automator(自動操作) 的軟體,可以幫助我們建立工作流程,我們可以藉助它來幫我們跑指令碼。
新建快速操作
開啟 Automator,新建一個快速操作:
配置開始上傳提示
這一步的目的是讓 AppleScript 彈出一個提示。
新增一個執行 AppleScript 指令碼:
在其中寫上:
on run {input, parameters}
display notification "⬆️ 開始上傳"
return input
end run
配置 shell 指令碼
增加一個執行 Shell 指令碼(注意使用 bash
來執行指令碼):
在其中寫上:
/usr/local/bin/python3 <<EOF
把上一步中配置好的 Python 指令碼複製到這裡
EOF
其中的 /usr/local/bin/python3 <<EOF
和 EOF
寫法是一個 Hack,如果直接選擇使用 python 執行,會出現找不到 Python 第三方庫的情況,所以用了這個 Hack 的辦法。
配置上傳結束提示
這一步的目的是顯示 Python 指令碼返回的字串,方便我們判斷圖片是否上傳成功。
新增一個執行 AppleScript 指令碼,在其中寫上:
on run {input, parameters}
-- 使用訊息通知顯示 python 輸出的字串
display notification input as string
return input
end run
最後儲存檔案(預設儲存位置是~/Library/Services
),到此已經配置完成。
設定快捷鍵
可以在設定中,為剛才建立的服務設定一個快捷鍵。
本作品採用《CC 協議》,轉載必須註明作者和本文連結