解决CopyQ在KDE环境下全局快捷键失效的问题

Copyq 在 kde 环境下全局快捷键不起作用,可能的原因是 copy 自启动之后与全局快捷键有冲突,具体现象是在 copyq 开启 auto start 之后,在 shortcut 系统设置里会出现两个 copyq 的快捷键设置,一个在 Applications 下面,一个在 System Services 。

这两个程序都会去注册全局快捷键,然后就会提示下面的错误

1
Dec 25 09:16:16 ThinkPad copyq[2156]: Warning: [qt.qpa.services] Failed to register with host portal QDBusError("org.freedesktop.portal.Error.Failed", "Could not register app ID: Connection already associated with an application ID")

解决办法:

  1. 在 copyq 设置了把全局快捷键删除,但是保留开启 auto start

  2. 在 kde 设置里面把 Applications 下面的 copyq 删除

  3. 然后添加一个 command 绑定到全局快捷键,command 内容如下:

    1
    /usr/bin/copyq -e "toggle()"

参考:

https://copyq.readthedocs.io/en/latest/faq.html#why-do-global-shortcuts-not-work

Linkedin API

最近有在看 LinkedIn 的 API 文档,在这里记录一下:

用户文章 API

获取用户发布的文章

LinkedIn API 曾经是支持经过用户授权后获取发布的文章的,相关的 OAuth scope 是 r_member_social ,但是 LinkedIn 移除了相关的 scope 和 API,就再也无法获取用户的文章了。

r_member_social is a closed permission

发布文章

需要的 scope w_member_social

公司组织 API

获取用户管理的公司组织

处理返回结果的时候要注意下 "state": "APPROVED" 才算是用户有权限管理的公司

获取公司组织详情

注意 URL 当中的公司组织 ID 是数字,比如 79988552

获取公司组织文章

需要的 scope r_organization_social

Sample Request

1
2
3
4
5
## Get Organization Posts By Organization
curl "https://api.linkedin.com/rest/posts?author=urn%3Ali%3Aorganization%3A104928924&q=author&count=10&sortBy=LAST_MODIFIED" \
-H 'X-Restli-Protocol-Version: 2.0.0' \
-H 'Linkedin-Version: 202408' \
-H 'Authorization: Bearer Token'

OAuth 权限说明

上面那些 API 主要用到下面几个权限

1
2

openid email profile w_member_social r_organization_social w_organization_social r_organization_admin
Permission Description
openid
email
profile
w_member_social 发布用户文章
r_organization_social 获取公司组织的文章
w_organization_social 发布公司组织的文章
r_organization_admin 获取用户管理的公司组织

其他

新版本 API

LinkedIn 在 2022 年的时候将 API 地址从 https://api.linkedin.com/v2/ 变更成了 https://api.linkedin.com/rest/ , 详情如下:

token 缓存 bug

LinkedIn 的 OAuth token 有个 5 分钟的缓存问题,即使你更换了新的 token,LinkedIn 后端仍然使用旧的 token,新 token 必须等待 5 分钟才能生效。例如,你新 token 添加了一些新的权限,但你请求相关权限 API 时仍然会提示权限不足,过了 5 分钟后就可以成功调用了。

相关链接

LinkedIn API postman

官方文档

Developer Apps

更新历史

  • 2024-09-06 首次更新

LinkedIn Twitter爬虫研究

TLDR

Twitter 和 LinkedIn 都需要登陆账号才能抓取到内容,不管你使用无头浏览器还是非公开的 API.

Detail

背景

项目需要抓取用户在 Twitter 和 LinkedIn 上发布的内容,但官方 API 无法满足需求。Twitter API 似乎只能获取最近 7 天的推文,而 LinkedIn 根本没有提供获取用户内容的 API。因此,需要研究其他抓取方式。

Twitter

尝试过用无头浏览器在不登录的情况下抓取推文,发现 Twitter 对不同的账号有不同的处理方式:

  • 有些账号在不登录的情况下可以获取到最新的推文,比如 nasa
  • 一些账号只能显示老的推文
  • 剩余部分的账号不登录无法查看推文

用无头浏览器的问题是你需要去解析 dom 来提取推文,比较麻烦。后来发现 GitHub 上有个名叫 trevorhobenshield/twitter-api-client 的库使用了未公开的 API 抓取推文:

APIFY 上有个类似的 actor 感觉也是用了这个库:

使用这个库需要登陆 Twitter 账号,有抓取频率限制,如果超出了限额会返回 429 状态码,如果在 serverless 那种经常变更 ip 的环境使用,会触发 Twitter 的安全策略,需要你手动登录账号输入验证码来解锁账号。

还有一个名叫 social tools 的第三方网站提供 API 来抓取推文,没有用过所以这里不做评价。

Twitter 对创建账号也有限制,需要邮箱认证和验证码,感觉验证码的问题可以用 AI 来解决。

说白了,就是得刷号才能抓到大量推文。

LinkedIn

LinkedIn 官方曾经提供过 API 来获取用户发布的文章,但是后来把这个接口给删除了,估计是担心被人抓取后用来训练 AI。

LinkedIn 也有那种使用非公开 api 的库,名叫 tomquirk/linkedin-api

同样也需要登录账号,LinkedIn 的安全策略比 Twitter 严格的多,手机号码验证,图形验证码。如果你的账号被锁定,LinkedIn 还需要你上传身份证才能解锁账号。

LinkedIn 官方提供 API,可在用户授权后获取用户管理的公司发布的文章

Github Copilot 使用体验

使用 GitHub Copilot 已经一年多了,来分享一下我的使用体验:

首先说优点:

代码优化助手

有时你觉得一段代码写得有点啰嗦,但没有查阅相关文档,你并不知道是否有更好的写法。这时 Copilot 就能提供一些更简洁的写法。

例如,我之前写 GitHub Actions 时遇到过这样一个问题:下面的代码是部分 Actions 的代码,它的功能是 SSH 到 VPS 上执行一些固定的脚本。由于我有多台 VPS,每多一台 VPS 都要添加一段类似的代码,唯一的区别是 VPS 的端口号、IP 地址等变量。

原始代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- name: Deploy to US
uses: appleboy/ssh-action@v1.0.3
env:
REALITY_SERVER_NAME: "www.xxx.com"
with:
host: "1.1.1.1:2222"
username: "root"
key: ${{ secrets.SSH_VPS }}
envs: REALITY_SERVER_NAME
script: |
scripts...

- name: Deploy to JP
if: ${{ success() }}
uses: appleboy/ssh-action@v1.0.3
env:
REALITY_SERVER_NAME: "www.xxx.com"
with:
host: "2.2.2.2:444"
username: "root"
key: ${{ secrets.SSH_VPS }}
envs: REALITY_SERVER_NAME
script: |
scripts...

我中途研究了一下 appleboy/ssh-action 的用法,想看看它是否支持多台服务器,但最终发现它不符合我的需求。我还查了一下 GitHub Actions 目前是否支持 YAML 锚点。最后我问了 Copilot:“Is this github action code a bit redundant, is there room for optimization?”

Copilot 随后给出了修改后的代码:

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
runs-on: ubuntu-latest
strategy:
matrix:
server:
- {
name: "server1",
host: "1.1.1.1:2222",
username: "root",
reality_server_name: "www.xxx.com",
}
- {
name: "server2",
host: "2.2.2.2:4444",
username: "root",
reality_server_name: "www.xxx.com",
}

steps:
- name: Deploy to ${{ matrix.server.name }}
uses: appleboy/ssh-action@v1.0.3
env:
REALITY_SERVER_NAME: ${{ matrix.server.reality_server_name }}
with:
host: ${{ matrix.server.host }}
username: ${{ matrix.server.username }}
key: ${{ secrets.SSH_VPS }}
envs: REALITY_SERVER_NAME
script: |
scripts...

如果没有 copilot 或者你没有看过一遍 github actions 的所有文档的话,你是不知道还有 matrix 这种用法的。

Demo 代码生成

有时候想用不熟悉的语言写个 Demo 程序,或者对框架和库不太熟悉的时候,Copilot 可以帮你快速写出示例代码。

冗余代码生成

copilot 特别适合生成一些 verbose code,特别是在写增删改查代码的时候,比如写一些 controller,生成一些 entity 代码。

接下来说一下缺点:

生成的代码可能包含一些不明显的 bug

我认为这是 Copilot 最大的缺点:它有时无法完全理解你的意图,生成的代码会包含一些不易察觉的 bug。比如以下代码(Kotlin,已简化):

1
2
3
4
5
6
val a = 1;
val b = 2;

function add(x:Int, y:Int): Int {
return x + y;
}

你本来意图是些下面这段代码:

1
val c = add (a, b)

但实际上 copilot 生成的这段代码

1
val c = add (a, a)

生成的代码会通过编译,如果你不去 review 一下你是很难发现这个 bug 的。

又或者下面这段代码:

1
2
3
4
5
val map = mutablMapOf<String,String>();

map.put("id" , a)
map.put("name" , b) -- 本来你想写的代码
map.put("username", b) -- copilot 生成的代码

本来要写的是 name 但是 copilot 生成的是 username ,这种 bug 也比较难发现。

数据库更新不及时

有时你想让 Copilot 生成某个框架的代码示例,但它只能给出旧版本的代码示例,因为 Copilot 的数据还没有包含最新版本的框架数据。

幻觉

这属于 LLM 的功能特性,而非 bug。例如,它生成的代码可能会调用一些不存在的方法,或者列出一些不存在的库。

插件支持

感觉 VS Code 上的 Copilot 比 JetBrains 上的好用,总觉得 JetBrains 上的 Copilot 有点笨。

总的来说,Copilot 有明显的优缺点。在使用 Copilot 生成的代码时,一定要仔细检查。如果使用得当,感觉可以提高不少效率。

infuse刮削逻辑研究

我最近研究了 Infuse 的刮削逻辑,发现它的官方文档写得不太清楚。我用 Infuse + 阿里云盘的方式测试了一下,总结如下:

剧集

1
2
3
folder1/foder2/file1.mkv
folder1/foder2/file2.mkv

  • 对于剧集来说,folder1folder2 的命名并不重要,Infuse 并不关心它们的名称。关键在于 file1 的文件名。如果你希望 Infuse 将 folder2 识别为一个剧集,那么 file1file2 的文件名必须遵循 剧集名称.第几季.第几集.后缀名 的格式,例如 Peppa.Pig.S01.E01.mkv 表示《小猪佩奇》第一季第一集。
  • 官方文档显示剧集信息源自 TMDB,但实际测试下来似乎并非如此。如有剧集名称疑问,可手动修改 file1 元数据,并参考搜索结果中的剧集名称进行命名。
  • 如需批量重命名文件,可以使用 Mountain Duck + Alist 挂载阿里云盘,然后利用 macOS 的批量重命名功能。Mountain Duck + 阿里云盘官方 WebDAV 无法重命名文件,会返回 403 错误。

排除文件夹

文档中的方法测试了下没有效果,不知到是啥原因,只能把文件夹移动到别的地方。

IO操作中阻塞线程的具体表现

在 I/O 操作中阻塞线程的具体表现:

  1. 系统调用层面:
    • 当程序执行 I/O 操作(如读取文件)时,它会发起一个系统调用。
    • 在传统的阻塞 I/O 模型中,这个系统调用会导致线程进入等待状态。
  2. 线程状态变化:
    • 线程从”运行”状态转变为”阻塞”状态。
    • 操作系统会将这个线程从 CPU 的执行队列中移除。
  3. CPU 资源释放:
    • 阻塞的线程不再占用 CPU 时间片。
    • CPU 可以切换到其他就绪的线程执行。
  4. 等待 I/O 完成:
    • 线程保持阻塞状态,直到 I/O 操作完成。
    • 完成可能需要相对较长的时间(相对于 CPU 速度而言)。
  5. 唤醒过程:
    • I/O 操作完成后(通常通过中断机制通知 CPU),操作系统将线程标记为就绪状态。
    • 线程重新进入就绪队列,等待被调度执行。
  6. 继续执行:
    • 当线程再次获得 CPU 时间片时,它从 I/O 操作的下一条指令继续执行。

阻塞的影响:

  • 资源利用率低:阻塞的线程无法执行其他任务,即使 I/O 操作耗时很长。
  • 并发处理能力受限:每个阻塞的 I/O 操作都可能需要一个专门的线程,限制了系统能同时处理的 I/O 操作数量。

java NIO

  • 非阻塞 I/O:
    • NIO 允许线程发起 I/O 操作后立即返回,而不是等待操作完成。
    • 线程可以继续执行其他任务,而不是被阻塞。
  • 多路复用:
    • NIO 使用选择器(Selector)来管理多个通道(Channel)。
    • 一个线程可以监控多个 I/O 操作的状态。
  • 工作原理:
    • 线程不会”阻塞然后去做别的事”,而是根本不会阻塞。
    • 它会持续检查多个 I/O 操作的状态,只在数据就绪时才进行实际的 I/O 操作。
  • 实际操作流程:
    a. 设置通道为非阻塞模式。
    b. 将多个通道注册到一个选择器上。
    c. 线程调用选择器的 select()方法。
    d. 选择器返回已经就绪的通道。
    e. 线程对就绪的通道执行 I/O 操作。

A context switch can occur while the kernel is executing a system call on behalf of the user. If the system call blocks because it is waiting for some event to occur, then the kernel can put the current process to sleep and switch to another process. For example, if a system call requires a disk access, the kernel can opt to perform a context switch and run another process instead of waiting for the data to arrive from the disk. Another example is the system call, which is an explicit request to put the calling process to sleep. In general, even if a system call does not block, the kernel can decide to perform a context switch rather than return control to the calling process.

I/O操作中阻塞线程的具体表现

在 I/O 操作中阻塞线程的具体表现:

  1. 系统调用层面:
    • 当程序执行 I/O 操作(如读取文件)时,它会发起一个系统调用。
    • 在传统的阻塞 I/O 模型中,这个系统调用会导致线程进入等待状态。
  2. 线程状态变化:
    • 线程从”运行”状态转变为”阻塞”状态。
    • 操作系统会将这个线程从 CPU 的执行队列中移除。
  3. CPU 资源释放:
    • 阻塞的线程不再占用 CPU 时间片。
    • CPU 可以切换到其他就绪的线程执行。
  4. 等待 I/O 完成:
    • 线程保持阻塞状态,直到 I/O 操作完成。
    • 完成可能需要相对较长的时间(相对于 CPU 速度而言)。
  5. 唤醒过程:
    • I/O 操作完成后(通常通过中断机制通知 CPU),操作系统将线程标记为就绪状态。
    • 线程重新进入就绪队列,等待被调度执行。
  6. 继续执行:
    • 当线程再次获得 CPU 时间片时,它从 I/O 操作的下一条指令继续执行。

阻塞的影响:

  • 资源利用率低:阻塞的线程无法执行其他任务,即使 I/O 操作耗时很长。
  • 并发处理能力受限:每个阻塞的 I/O 操作都可能需要一个专门的线程,限制了系统能同时处理的 I/O 操作数量。

java NIO

  • 非阻塞 I/O:
    • NIO 允许线程发起 I/O 操作后立即返回,而不是等待操作完成。
    • 线程可以继续执行其他任务,而不是被阻塞。
  • 多路复用:
    • NIO 使用选择器(Selector)来管理多个通道(Channel)。
    • 一个线程可以监控多个 I/O 操作的状态。
  • 工作原理:
    • 线程不会”阻塞然后去做别的事”,而是根本不会阻塞。
    • 它会持续检查多个 I/O 操作的状态,只在数据就绪时才进行实际的 I/O 操作。
  • 实际操作流程:
    a. 设置通道为非阻塞模式。
    b. 将多个通道注册到一个选择器上。
    c. 线程调用选择器的 select()方法。
    d. 选择器返回已经就绪的通道。
    e. 线程对就绪的通道执行 I/O 操作。

A context switch can occur while the kernel is executing a system call on behalf of the user. If the system call blocks because it is waiting for some event to occur, then the kernel can put the current process to sleep and switch to another process. For example, if a system call requires a disk access, the kernel can opt to perform a context switch and run another process instead of waiting for the data to arrive from the disk. Another example is the system call, which is an explicit request to put the calling process to sleep. In general, even if a system call does not block, the kernel can decide to perform a context switch rather than return control to the calling process.

远程打印研究

每年枇杷季,家里都要手写几百张快递单,填到怀疑人生。以前就想找更便捷的填单方式,后来发现可以用快递平台的网站填好单,再用热敏打印机打印。但家里老人不会用电脑,平时我们也不在老家,就想着能不能用远程打印的方式,人在外地填好单,连接到老家的打印机,直接打印出来。

研究了有以下几种远程打印方式:

云打印机

淘宝上有卖那种云打印功能的打印机,貌似用的是 4g 流量,每年要交钱的样子

阿里云打印

阿里云打印只支持 A3、A4、A5 三种打印尺寸,热敏打印机纸张尺寸特殊,所以放弃该方案。

内网穿透

最终用的是这一套方案,方法如下:

  • 在两地的电脑安装软件 tailscale
  • 热敏打印机连接到老家的电脑上,开启打印机共享
  • 两边电脑连接 tailscale 的情况下,在另一台电脑上添加老家的打印机
  • 快递平台打印快递单的时候选择远程打印机

这套方案用下来有几个问题:

打印机卡纸

远程打印经常卡纸,同一个网络下就很少卡,可能是网速和 Windows 问题。网上看到一篇文章,怀疑是打印机缓存设置问题,明年调整配置再试一下。

延迟

可能是 tailscale 的问题,有时候发出打印请求后要过差不多几十秒才能打印出来

2025-05-19

windows 烂泥扶不上墙,换成 debian + cups + tailscale 方案了,目前非常稳定,没有发生过卡纸

Dropbox Operation not permitted 问题修复

Dropbox 在 macOS Ventura 中将同步目录从 ~/Dropbox 移至 /Users/xxx/Library/CloudStorage/Dropbox 后,使用 iTerm ls 命令访问该目录会提示 Operation not permitted 错误。这是因为 iTerm 对新目录没有访问权限。

解决方法:打开 system settingsPrivacy&SecurityFull Disk AccessiTerm,为 iTerm 启用访问权限即可。

这里还有一个问题就是如果你将 ~/.ssh 目录符号链接到同步文件夹会有权限问题,同步文件夹的上级目录的权限是不一样的。

2024-03-16 水

我还活着 。。。

最近把家里的黑苹果升级成了 Sonoma,苹果在 Sonoma 版本移除了博通网卡驱动,这导致无线没法用了,突然有点想换回 Windows 了。