这篇文章是用来补充之前我之前发的 Typora + 图床的视频,具体效果可以看以下视频,视频中介绍了我的实现思路和具体效果。因为图床域名和工具的更新,视频中有些地方不再适用,看到这个视频时不时还有播放和点赞(其实没几个😂),决定补充下。
原视频中表述可能略显啰嗦,目的是为了让大家知其所以然,将过程分析出来,这样大家遇到什么问题,都可以按照思路解决。例如有一次路过图床的域名改了,如果你看了我的视频,你肯定可以知道在哪里配置这个链接。

配置步骤
1. 安装配置 Node.js
实现图片上传需要用到 Node.js,安装和配置方式自行搜索,这里不做赘述。
2. npm 安装 picgo,修改上传模块代码
执行命令安装 picgo,请务必安装 1.4.4 版本。
1
| npm install -g picgo@1.4.4
|
然后进入 Node.js 全局包路径,找到 picgo 模块,编辑 picgo\dist\src\plugins\uploader\smms.js 文件,替换为以下内容保存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| "use strict"; Object.defineProperty(exports, "__esModule", { value: true });
const postOptions = (fileName, image, config) => { return { method: 'POST', url: 'https://imgse.com/json', headers: { contentType: 'multipart/form-data', 'User-Agent': 'PicGo', 'Cookie': config.Cookie }, formData: { auth_token: config.auth_token, type: 'file', action: 'upload', source: { value: image, options: { filename: fileName } } } }; };
const handle = async (ctx) => { const smmsConfig = ctx.getConfig('picBed.smms'); if (!smmsConfig) { throw new Error('Can\'t find smms config, please provide api token, see https://sm.ms/home/apitoken'); } const imgList = ctx.output; for (const img of imgList) { if (img.fileName && img.buffer) { let image = img.buffer; if (!image && img.base64Image) { image = Buffer.from(img.base64Image, 'base64'); } const postConfig = postOptions(img.fileName, image, smmsConfig); let body = await ctx.Request.request(postConfig); body = JSON.parse(body);
if (body.status_code === 200) { delete img.base64Image; delete img.buffer; img.imgUrl = body.image.url; } else { ctx.emit('notification', { title: '上传失败', body: body.error.message }); throw new Error(body.error.message); } } } return ctx; };
const config = (ctx) => { const userConfig = ctx.getConfig('picBed.smms') || {}; const config = [ { name: 'token', message: 'api token', type: 'input', default: userConfig.token || '', required: true } ]; return config; };
exports.default = { name: 'SM.MS图床', handle, config };
|
3. 配置 Typora,设置为命令行上传
文件 > 偏好设置 > 图像 > 上传服务设定,上传服务选择 Custom Command,命令填写格式:[node路径] [picgo路径] upload,示例如下,根据自己的实际安装路径填写。
1
| C:\Develop\nodejs\node C:\Develop\nodejs\node_global\node_modules\picgo\bin\picgo upload
|
4. 编辑配置文件,配置路过图床的 cookie 和 token
创建配置文件,路径:C:\Users$username.picgo\config.json,内容如下,cookie 和 token 的获取方式见原视频。
1 2 3 4 5 6 7 8 9 10 11 12
|
{ "picBed": { "smms": { "Cookie": "自行替换为路过图床的cookie", "auth_token": "自行替换为路过图床的token" }, "uploader": "smms" }, "picgoPlugins": {} }
|
FAQ
1. token找不到?
试试查看路过图床的网页源代码,搜索 token。
2. cookie 和 token 过期,总是要刷新吗?
是的,路过图床没有提供相关 API。我是一种思路的写一个定时任务,定时从路过图床获取 cookie 和 token,刷新到本地配置文件中。以下是我的 Java 实现,写的不好,大家可以自行使用自己擅长的语言实现,这里只提供一种思路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| package top.y1j;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.*; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate;
import java.io.FileWriter; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map;
public class RefreshTokenJob { private static final Logger log = LoggerFactory.getLogger(RefreshTokenJob.class);
private String tokenPrefix = "PF.obj.config.auth_token = \"" ; private int tokenLength = 40; private String homePageUrl = "https://imgse.com/login"; private String loginUrl = "https://imgse.com/login"; private String filePath = "C:\\Users\\${User}\\.picgo\\config.json"; private String username = "账号"; private String password = "密码"; private RestTemplate restTemplate = new RestTemplate() ;
@Scheduled(cron = "0 0/25 * * * ? ") public void execute() throws Exception { log.info("访问路过图床主页, 获取token和cookie"); HttpHeaders startHeader = new HttpHeaders(); startHeader.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.3.5211 SLBChan/112"); HttpEntity<MultiValueMap<String, String>> startRequest = new HttpEntity<>(startHeader); URI uri = new URI(homePageUrl);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.POST, startRequest, String.class);
StringBuilder cookieBuilder = new StringBuilder(); List<String> cookieList = response.getHeaders().get("Set-Cookie"); for (String item : cookieList) { String substring = item.substring(0, item.indexOf(";") + 1); cookieBuilder.append(substring); } String cookie = cookieBuilder.toString(); String body = response.getBody(); int index = body.indexOf(tokenPrefix) + tokenPrefix.length(); String token = body.substring(index, index + tokenLength); log.info("拿到数据, 开始登录, token: {}, cookie: {}", token, cookie); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.add("cookie", cookie); headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.3.5211 SLBChan/112"); MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("login-subject", username); params.add("password", password); params.add("auth_token", token); HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers); ResponseEntity<String> loginResponse = restTemplate.exchange(loginUrl, HttpMethod.POST, requestEntity, String.class); List<String> loginCookieList = loginResponse.getHeaders().get("Set-Cookie"); for (String item : loginCookieList) { String substring = item.substring(0, item.indexOf(";") + 1); cookieBuilder.append(substring); } Map<String, Object> config = this.getConfig(token, cookieBuilder.toString()); ObjectMapper mapper = new ObjectMapper(); String configJson = mapper.writeValueAsString(config); FileWriter fileWriter = new FileWriter(filePath); fileWriter.write(configJson); fileWriter.close(); log.info("配置更新成功"); }
private Map<String, Object> getConfig(String token, String cookie) { Map<String, Object> config = new HashMap<>(); Map<String, Object> picBed = new HashMap<>(); Map<String, Object> smms = new HashMap<>(); smms.put("auth_token", token); smms.put("Cookie", cookie); picBed.put("smms", smms); picBed.put("uploader", "smms"); config.put("picBed", picBed); return config; }
public static void main(String[] args) throws Exception { RefreshTokenJob refreshTokenJob = new RefreshTokenJob(); refreshTokenJob.execute(); } }
|