逃离豆瓣之豆瓣代替服务

这篇笔记新建的时间是 2020 年 12 月 29 号,想来从那个时间点开始我就一直想着怎么离开豆瓣了。过去一年时间里面陆陆续续也发现了不少不错的网站,甚至有一些比豆瓣都要好用。这里就再整理一下。

豆瓣让我不能忍受的便是对词条的删减,以及对用户笔记,影评,书评的肆意审查,基本导致了现在豆瓣陷入不可用的状态。

我也曾经说过,我离不开豆瓣的几个理由:

  • 我过去几千条的标注
  • 豆瓣关注的有趣的灵魂
  • 还有无数的有价值的影评,书评

豆瓣电影 剧集

NeoDB

NeoDB 是一个建立在 federated network (联邦网络)中的用来标记书籍、电影、音乐和游戏的网站。

NeoDB 目前只能通过 [[Mastodon]] (或[[Pleroma]]/Friendica/PixelFed)实例的账号来登录。

我的页面:https://neodb.social/users/einverne@m.einverne.info/

themoviedb

themoviedb 简称为 TMDB ,是一个从 2008 年开始的电影,剧集数据库。拥有非常全的数据库。

TMDB 也开放了编辑入口,所有的注册用户都可以贡献,和当年的豆瓣非常相似,官方也有非常详细的 贡献指南

themoviedb

看网站的设计,词条的界面,数据也非常详细,设计也不错。

themoviedb movie item

Trake.tv

[[trakt]] 是一个电视剧和电影媒体资源订阅追踪平台,电视界的 IMDB。可以认为是一个电视剧的数据库,有每个电视剧的元数据,至少包括剧名、首播时间、是否完结、长度、季、集、语言、国家、简介、类别、演员,链接到官网,IMDB,TMDB,TVDB,Wiki 等的链接等等。而且这些数据是公开的,有非常多 App 在使用他作为基础数据提供其他服务。

Trakt 相较于豆瓣更好的地方在于可以和第三方的应用交互,比如在 Plex 中看完一集之后可以自动同步到 trake。

Trakt 还支持 [[Kodi]], [[Plex]], [[Emby]], [[Netflix]], [[Infuse]], [[Jellyfin]], [[MediaPortal]], [[MrMC]], [[Stremio]], [[Serviio]], [[VLC]] 等等。

trakt-vip

Trakt 还提供了 VIP 增值服务,包括了如上的功能。个人 30$ 一年起步,还有另外一个是 60$ 一年。

LetterBoxd

LitterBoxd 是另一个可以标记看过电影的网站。不过 LetterBoxd 只支持电影。

首页:

letterboxd

词条页面

letterboxd item

TVDB

TBDB 是专注在剧集的网站。

IMDB

IMDB 就不用多说了,老牌的电影资料站。

豆瓣读书

Google Books

https://books.google.com

  1. 支持图书目录预览,支持标题,ISBN 搜索,支持浏览记录等等
  2. 支持标注想读(To read),在读(Reading now),读过(Have read),支持打分,甚至也是 1-5 分,支持填写 review
  3. 支持一键链接到网络商城购买,支持跳转到 Google Play 购买电子版

Google Book 的 API 文档:

google book search

Goodreads

Amazon 收购而来的网站,和 Kindle 搭配使用。

thestorygraph

可以用来追踪阅读进度,以及管理看过书籍。

豆瓣音乐

本人不怎么使用豆瓣音乐,所以没怎么整理,不过 Last.FM 已经存在很多年了。数据也比较全。


2022-05-12 douban , movie , book management , personal-data , track , 豆瓣 , douban

Proxmox 扩展 VM 虚拟机磁盘容量

之前在 Proxmox 上给 Ubuntu 划分了 64GB 的空间,运行一段时间之后磁盘空间剩余不多,就抽时间扩展一下。本文就记录一下给 Proxmox VE 的虚拟机扩展的过程。其实之前的文章里面也略微提到过一些,但是没有完整记录。

本来想着是这一篇文章把虚拟机的扩展和缩减空间一并整理了,但写着写着篇幅就比较大了,本文最后还是集中在扩容部分,缩减(shrink) 部分有机会再整理吧。

扩容之前

在扩容之前,为了防止发生错误,请先备份虚拟机,然后关闭虚拟机操作。

关于备份的操作可以参考: Proxmox VE 下备份和恢复虚拟机

虚拟机磁盘扩容

在 Proxmox VE 管理后台,点击虚拟机,在 Hardware 中选中 Hard Disk,然后在菜单栏中就能看到 Resize disk

proxmox resize vm disk

不过需要注意的是,这里的只能给虚拟机的磁盘增加容量,而不能缩小容量,关于缩小容量的操作以后有机会再写。

图中可以看到原始的虚拟机磁盘分配了 64GB,我又扩容了 64GB。

扩容之后启动虚拟机,SSH 登录,然后执行 df -h

Filesystem      Size  Used Avail Use% Mounted on
udev            7.8G     0  7.8G   0% /dev
tmpfs           1.6G  1.5M  1.6G   1% /run
/dev/sda2        63G   38G   23G  63% /
tmpfs           7.9G  4.0K  7.9G   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           7.9G     0  7.9G   0% /sys/fs/cgroup
/dev/loop0       56M   56M     0 100% /snap/core18/2344
/dev/loop2       62M   62M     0 100% /snap/core20/1434
/dev/loop1       56M   56M     0 100% /snap/core18/2409
mergerfs        5.4T  4.6T  510G  91% /mnt/storage
/dev/loop3       68M   68M     0 100% /snap/lxd/22753
/dev/loop6       44M   44M     0 100% /snap/snapd/15177
/dev/loop7       62M   62M     0 100% /snap/core20/1405
/dev/loop5       45M   45M     0 100% /snap/snapd/15534
/dev/loop4       68M   68M     0 100% /snap/lxd/22526
/dev/sdd1       1.8T  1.6T  196G  89% /mnt/sdb1
/dev/sdb1       1.8T  1.6T  117G  94% /mnt/sdd1
/dev/sdc1       1.8T  1.6T  198G  89% /mnt/sdc1
tmpfs           1.6G     0  1.6G   0% /run/user/1000

可以看到系统分区的容量 /dev/sda2 并没有扩展。

还可以用 sudo fdisk -l 来查看。

然后检查一下分区,执行 sudo lsblk

❯ sudo lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0    7:0    0 55.5M  1 loop /snap/core18/2344
loop1    7:1    0 55.5M  1 loop /snap/core18/2409
loop2    7:2    0 61.9M  1 loop /snap/core20/1434
loop3    7:3    0 67.8M  1 loop /snap/lxd/22753
loop4    7:4    0 67.9M  1 loop /snap/lxd/22526
loop5    7:5    0 44.7M  1 loop /snap/snapd/15534
loop6    7:6    0 43.6M  1 loop /snap/snapd/15177
loop7    7:7    0 61.9M  1 loop /snap/core20/1405
sda      8:0    0  128G  0 disk
├─sda1   8:1    0    1M  0 part
└─sda2   8:2    0   64G  0 part /

可以看到系统的分区 sda2 确实是没有完全占用全部的磁盘(sda)。这个时候我们只需要扩展一下系统分区即可。

我们可以使用很多种方式(parted, growpart, cfdisk)扩展分区,这里我们就使用 growpart 命令。

在 Debian 和 Ubuntu 下 growpart 命令在 cloud-guest-utils 包中。

注意这里的数字 2 要替换成自己的分区号。

sudo growpart /dev/sda 2

结果:

❯ sudo growpart /dev/sda 2
CHANGED: partition=2 start=4096 old: size=134211584 end=134215680 new: size=268431327 end=268435423

没有使用 [[LVM]],就使用 resize2fs,执行:

sudo resize2fs /dev/sda2

执行结果:

❯ sudo resize2fs /dev/sda2
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/sda2 is mounted on /; on-line resizing required
old_desc_blocks = 8, new_desc_blocks = 16
The filesystem on /dev/sda2 is now 33553915 (4k) blocks long.

之后在查询 df -h 就看到空间完美的被使用了。

如果使用了 LVM,需要执行如下步骤:

sudo pvresize /dev/sda2

更新逻辑卷的大小:

sudo lvresize --extents +100%FREE --resizefs /dev/mapper/ubuntu--vg-ubuntu--lv

reference


2022-05-10 proxmox , pve , linux , vm , virtual-machine

现代性与大屠杀读书笔记

属于 [[20220417-21 天计划]] 的第3本书。

什么是现代性

[[现代性]]是指的现代社会所具有的一些典型特征。现代(modern)一词16世纪才被创造出来。字面上的含义是「当下或此刻」。人们有了时间的概念,生活不再周而往复。

这本书中对现代性的解释大致分为两个层面:

  • 精神层面,理性的精神,控制的欲望,人类想要认识一切、改造一切的精神
  • 制度层面,高效而有序的社会组织形态

为什么会发生犹太人大屠杀

  • 思想上
    • 不是传统的反犹主义,而是一种现代的思想,[[园艺文化]] 和 [[种族主义]]
    • 历史上的犹太人流落到欧洲的各处,属于从属地位,帮贵族收租,做些小买卖,成为了夹在贵族和平民之间的中间人,收到两边的歧视和厌恶
    • 崇尚理性、高效的现代化进程有一种园艺文化,在德国纳粹人严重犹太人就是杂草
    • [[种族主义]] 达到顶峰,保证日耳曼的血统纯正
  • 制度上
    • 现代[[官僚制度]]
    • 对犹太人进行精确的定义,纽伦堡法案,对犹太人进行登记
    • 将犹太人和其他德国人隔开
    • 着手将犹太人驱逐出德国疆域
      • 希姆莱 1940年在备忘录中写到,不想采用从肉体上消灭整个民族的做法,不德国,也不可能实现
      • 海德里希,种族灭绝对德国人这个文明的民族来说是不体面的
      • 遇到问题,找不到地方驱逐犹太人
        • [[艾希曼]],前往海法、开罗,研究将犹太人移居巴勒斯坦的可能性
        • 马达加斯加方案
        • 整体绝育手术
      • 战争的进行,升级成将犹太人驱逐出整个欧洲
      • 肉体消灭成为了清洗犹太人最有效的方式
      • 最终解决方案
      • 定义、隔离、驱逐、屠杀
    • 现代官僚制度是大屠杀发生的根本原因
  • 技术上
    • 现代工业制度才造就了灭绝营、毒气室
    • 大屠杀的主要方式灭绝营、毒气室都是现代性的产物
    • 大工业的设施和流程,现代化的分工和管理制
    • 奥斯威辛在4年里屠杀了100万,1943年,1天可以屠杀4万3千人,只有现代大工业才能产生这样的结果
    • 毒气出自先进的化学工业,铁路网向集中营输送犹太人

官僚体制中的人摆脱了道德上的谴责。 冷静、高效、专业的完成自己的工作。

为什么这些正常人能摆脱道德上的自责呢?

  • 首先,因为官僚制度,等级分明,在权力的等级序列中,就是听从上级的命令,遵守组织的纪律,每个人考虑的不是自己这么做的后果,而是有没有完成上级的任务,技术责任代替了道德责任,成为了一个人需要担负的主要责任,人们可以心安理得的将道德责任归咎于上级,甚至堂而皇之为自己辩护,「我只是做了我被要求做的事情」。[[201912211716-艾希曼在耶路撒冷]]
  • 现代社会,职能和职位的细致分工模糊了人的道德感,犹太人大屠杀的任务中每个人只是整个庞大机器上的一个螺丝钉,很多人不知道自己的行为会有什么后果,在办公室里制定火车时刻表的职员从未见过毒气室中的惨状。
  • 灭绝营,毒气室,大大降低了执行者在杀戮时可能产生的道德同情,现代心理学的研究已经表明距离越远,越不容易产生道德同情
    • 战争的现代化,让杀戮成为了距离和技术的问题,军事实力越强,距离敌方越远,杀戮越容易

受害方的现代性

犹太人是受害者,但鲍曼说犹太人也负有责任,是大屠杀的帮凶,这些犹太人受到理性的驱动。而理性也是现代性的一个特征。

  • 犹太委员会,提供记录,劝说犹太人隔离
  • 协助纳粹设定名单,决定哪些同胞在哪些时候上火车,奉行的原则是牺牲少数拯救多数,如果不送一部分同胞去死,纳粹会杀死所有人。
  • 最后是大多数犹太人的「自我保全」的理性,为了活下去可以做任何事情,包括亲手去处理大屠杀产生的尸体

三句话总结书的内容

鲍曼在这本书中提出了一个骇人听闻的观点:「德国纳粹在二战期间实行的对犹太人的种族灭绝是现代性的表现」。

  • 思想上,种族灭绝计划和园艺文化、种族主义息息相关
  • 制度上,大屠杀与现代官僚制度紧密关联
  • 技术上,大屠杀充分利用了现代技术

现代官僚制度和现代技术还让屠杀犹太人的纳粹分子在执行任务时摆脱了道德上的困扰。

启发或想法

道德,对他人无条件的责任

现代性体制会压制道德,现代官僚体系会让技术责任代替道德责任,现代社会的原子化倾向会让人们成为互相隔离的冷漠个体。但正因为如此,才更需要重视道德,在任何情况下,一个人都要承担其自己的道德责任,不管发生什么,他都应该去做对的事情。这是避免下一次大屠杀发生的唯一方式。


2022-05-08 reading , reading-2022 , 现代性 , 大屠杀

解决 Adobe Premiere 不支持 mkv 问题

一直想学习一下视频剪辑,这两天正好拿一个韩剧试一下,但没想到第一步导入就被拦在了外面,不过还好,正好可以学习一下 mkv 格式,以及基本的视频格式。

我在将 mkv 格式的文件导入到 Adobe Premiere 的时候报错:

File format not supported.

mkv 格式

mkv 的全称是 Matroska Video File,是一种开放的多媒体档案封装格式,可以将不同编码的影片,音轨,字幕封装到同一个档案中。通常的扩展名是 .mkv, .mka , .mks 等等。1

为什么 Adobe 不支持 mkv 格式

Adobe 从 2019.1.5 版本开始就放弃支持 mkv 格式了2

本质上 mkv 是一个封装格式,Adobe Premiere 还是支持编辑其中封装的视频内容的。

使用 ffmpeg 提取 mp4 格式

首先安装 ffmpeg,然后执行:

ffmpeg -i "original_filename.mkv" -codec copy output_name.mp4

这一行命令不会进行转码,所以提取速度约等于文件拷贝的速度,非常快。

容器和编码方式

上面提到过 mkv 是一种媒体容器,可以将不同编码类型的数据包含到一起。而编码方式则是决定了视频、音频的压缩算法。

可以通过 ffmpeg -i filename.mkv 来查看文件的具体详情。

以一个最简单的例子,为方便学习输出内容有省略:

❯ ffmpeg -i Going.to.You.at.a.Speed.of.493km.S01E04.1080p.DSNP.WEB-DL.AAC2.0.H.264-NYH.mkv
ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers
  built with Apple clang version 13.1.6 (clang-1316.0.21.2)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/5.0.1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, matroska,webm, from 'Going.to.You.at.a.Speed.of.493km.S01E04.1080p.DSNP.WEB-DL.AAC2.0.H.264-NYH.mkv':
  Metadata:
    encoder         : libebml v1.4.2 + libmatroska v1.6.4
  Duration: 01:03:10.83, start: 0.000000, bitrate: 5704 kb/s
  Chapters:
    Chapter #0:0: start 1.001000, end 40.999000
      Metadata:
        title           : Intro
    Chapter #0:1: start 40.999000, end 3748.957000
      Metadata:
        title           : Scene 1
    Chapter #0:2: start 3748.957000, end 3790.826000
      Metadata:
        title           : Credits
  Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn (default)
    Metadata:
      BPS             : 5575824
      DURATION        : 01:03:10.787000000
      NUMBER_OF_FRAMES: 90888
      NUMBER_OF_BYTES : 2642095527
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
  Stream #0:1(kor): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
    Metadata:
      BPS             : 125375
      DURATION        : 01:03:10.826000000
      NUMBER_OF_FRAMES: 177695
      NUMBER_OF_BYTES : 59409362
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
  Stream #0:2(kor): Subtitle: subrip
    Metadata:
      title           : SDH
      BPS             : 74
      DURATION        : 01:03:00.359000000
      NUMBER_OF_FRAMES: 1167
      NUMBER_OF_BYTES : 35163
      _STATISTICS_WRITING_APP: mkvmerge v67.0.0 ('Under Stars') 64-bit
      _STATISTI

可以看到其中有三段 Stream,可以看到第一段是视频,第二段是音频,而第三段则是字幕,为了方便这里省略了后面还有的多语言字幕。

在每一段中可以看到其编码方案比如视频是 h264, 音频是 aac。

H.264 是一种视频编码,H.264 标准制定的目的就是为了创建一个更好的视频压缩标准,可以在更低的比特率的情况下可以提供更好的视频质量。


2022-05-07 adobe , adobe-premiere , mkv , ffmpeg , macos , handbrake

Go 语言学习笔记 7:容器

Go 语言中常见的容器。

数组

var name [size]T

举例:

var classMates [3]string

# or

classMates2 := [...]string{"A", "B", "C"}

切片

切片是对数组的一个连续片段的引用,容量可变的序列。动态数组。

内部结构包括底层数组指针、大小和容量。

  • array 指向底层存储数组的指针
  • len 切片长度
  • cap 切片容量,总是大于等于 len

从原数组中生成一个切片:

slice := source[begin:end]

举例:

source := [...]int{1,2,3}
sli := source[0:1]

动态创建切片,可以通过 make 函数动态创建切片

make([]T, size, cap)
  • T 是切片中的元素类型
  • size 长度
  • cap 预先分配的长度,容量

直接声明新的切片,不需要指定大小:

var name []T

比如:

ex := []int{1,2,3}

对切片的操作

append

append 函数可以向切片添加元素,返回新的切片。

copy

复制切片内容

copy(destSli, srcSli []T)

列表和字典

列表,链表

Go 通过双向链表实现,插入、删除非常高效。

var names list.List
name := list.New()

字典

映射关系,内部通过散列表方式实现。

name := make(map[KeyType]valueType)
package main

import "fmt"

func main() {
    classMate := map[string]string{
        "1": "EV",
        "2": "EV2",
    }
    fmt.Println(classMate)

    classMate1 := make(map[int]string)
    classMate1[0] = "EV"
    classMate1[1] = "EV1"
    fmt.Println(classMate1)

    mate, ok := classMate1[0]
    fmt.Println(mate, ok)
}

容器遍历

通过 for-range 语法

// 数组
nums := [...]int{1, 2, 3, 4, 5, 4, 3, 2, 1}
for k, v := range nums {
    fmt.Println(k, v)
}

// 切片
slis := []int{1, 2, 3, 4, 5, 4, 3, 2, 1}  
for k, v := range slis {  
   println(k, v)  
}

// map
// traverse map
for k, v := range classMate1 {
    fmt.Println(k, v)
}

2022-05-05 golang , google , programming , programming-language

每天学习一个命令:growpart 扩容分区

前端时间给 Proxmox VE 下的虚拟机扩容的时候留意到了这个 growpart 命令,专门用来给分区进行扩容的命令。

growpart - extend a partition in a partition table to fill available space

growpart 工具完成 Linux 系统盘分区扩容及文件系统扩展

Installation

Ubuntu 下可以直接安装:

sudo apt install cloud-guest-utils

使用

注意,对磁盘进行操作是高风险操作,如果对命令不熟悉,请先做好数据的备份,然后再进行操作,或实验。

我以我自己的实际情况为例,我有一个 Proxmox VE 的虚拟机因为磁盘内容告警,所以扩容了一倍,从 64G 扩容到 128GB。

在 Proxmox VE 中停止虚拟机之后扩容,然后启动虚拟机进入系统操作。

首先使用 fdisk -l 来查看磁盘分区信息,可以看到目前系统的分区还是没有改变,但是可以看到磁盘已经有剩余空间了。

因为我这里比较简单,我只想把剩余的空间分配给我当前的系统分区,所以可以直接使用 growpart,如果你还需要复杂操作,比如再划分一个分区之类的,可以考虑 [[parted]] 等命令。

还可以使用 lsblk 再确认一下。

因为我的系统分区是 /dev/sda 磁盘的第二个分区,所以运行 growpart 命令扩容分区

growpart /dev/sda 2

然后再执行以下命令,扩容 ext 文件系统

resize2fs /dev/sda2

再查看磁盘:

df -h
lsblk
fdisk -l

总结

growpart 命令可以非常方便的将分区扩展到全部的磁盘空间,不过需要注意的是,我的例子中 /dev/sda2 分区是磁盘的最后一个分区,如果你要扩容的分区在分区中间,可能需要考虑其他方案。

相关

  • [[gparted]]
  • [[2018-04-03-parted-linux-partition]]
  • [[2016-04-02-fdisk]]
  • [[lsblk]]

2022-05-03 linux , drive , growpart , partition , cli

aiohttp 使用笔记

最近想找一个 [[Wallabag]] 的 Python 客户端,在 GitHub 简单搜寻了一下之后发现了 wallbag_api 这个仓库,看了一下 Python 代码之后发现库中的代码是用 aiohttp 编写的,所以就来学习一下这个 Python 的异步 HTTP 库 aiohttp。

aiohttp 官方简洁明了,Asynchronous HTTP Client/Server for asyncio and Python. aiohttp 是一个基于 asyncio 模块的异步 HTTP 客户端/服务端框架。

可以 看到 aiohttp 不仅是一个 HTTP 客户端,也可以作为服务端。同时支持服务端的 WebSockets 和客户端 WebSockets。

我们知道 Python 下还有一个比较著名的 HTTP Client 库叫做 requests,这是一个同步的 HTTP 调用客户端,使用 requests 发起 HTTP 调用之后需要同步等待返回结果,而在 aiohttp 可以在发起请求之后将将程序的控制权暂时给别人,等待响应返回结果回来了之后再进行处理,这就可以提升系统的性能。

aiohttp 内部使用了 [[python-asyncio]] 来实现,而 Python 下 asyncio 的核心就是 [[Coroutine 协程]]

Coroutine 协程

Coroutine(协程)是一个更通用的 subroutine(子程序)。

async 方法中使用 await 关键字来表示 coroutine。当使用 await 关键字的时候,coroutine 会将当前程序的控制释放给 Event loop。

import asyncio
async def async_func():
    print('start ...')
    await asyncio.sleep(1)
    print('... end!')

async def main():
    async_func()#this will do nothing because coroutine object is created but not awaited
    await async_func()

asyncio.run(main())

如果直接调用 async_func() 不会有任何作用,需要在前面添加 await

协程适合 IO 密集型任务:

  • 网络请求,比如爬虫 [[aiohttp]]
  • 文件读写,[[aiofile]]
  • Web 框架,[[aiohttp]], [[FastAPI]]
  • 数据库查询,[[asyncpg]], [[databases]], [[aiomysql]]

Installation

安装使用:

pip install aiohttp

作为客户端

aiohttp 作为客户端。

这里可以和 requests 做一个简单的对比,在 requests 中发起同步请求:

import requests 
def hello()    
     return requests.get("http://httpbin.org/get")     

print(hello())

程序在 requests.get 方法调用时会同步等待请求返回。

而如果使用 aiohttp:

#!/usr/local/bin/python3.6
import asyncio 
from aiohttp import ClientSession 

async def hello():     
    async with ClientSession() as session:         
        async with session.get("http://httpbin.org/headers") as response:                
            response = await response.read()                         
            print(response) 
  
loop = asyncio.get_event_loop() 
loop.run_until_complete(hello())

在这个异步代码中我们可以看到很多的异步关键字,async 以及 await 关键字定义函数为异步。

这里使用 ClientSession() 获取一个 Session,session 可以在多个请求之间保留 cookie 和相关信息。因为 session 关闭是一个异步操作,所以需要使用 async with

session.get 发起调用,也是一个异步操作,所以也需要使用 async,而 with 语句保证 response 可以正确关闭。

最后为了让这个异步方法可以执行,需要将其放入一个事件循环。

作为服务端

[[用 aiohttp 写服务器]] 不是本文的重点,所以简单了解一下,先略过。

from aiohttp import web

routes = web.RouteTableDef()

@routes.get('/')
async def hello(request):
    return web.Response(text="Hello, world")

app = web.Application()
app.add_routes(routes)
web.run_app(app)

控制并发

使用 Semaphore 控制

Semaphore 是一个线程计数器,核心是 acquire()release() 方法。

执行 acquire() 方法时,先判断内部值是否小于 0,如果大于 0,获得锁,内部值减一,如果小于 0,阻塞,直到 release() 方法释放锁,内部值加一。

async def fetch(url, semaphore):
    async with semaphore:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                data = await response.text()
                print('data', data + " " + time.ctime())
                return data

async def run():
    url = 'http://127.0.0.1:5000'
    semaphore = asyncio.Semaphore(2)  # 限制并发量为2
    to_get = [fetch(url, semaphore) for _ in range(10)]
    await asyncio.wait(to_get)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())
    loop.close()

使用 TCPConnector 控制

async def fetch(session, url):
    async with session.get(url) as resp:
        if resp.status != 200:
            resp.raise_for_status()
        data = await resp.text()
        print('data', data + " " + time.ctime())
        return data

async def fetch_multi(session, urls):
    tasks = []
    for url in urls:
        task = asyncio.create_task(fetch(session, url))
        tasks.append(task)
    # gather: 搜集所有future对象,并等待返回
    results = await asyncio.gather(*tasks)
    return results

async def main():
    urls = ["http://127.0.0.1:5000/" for _ in range(10)]
    conn = aiohttp.TCPConnector(limit=3)
    async with aiohttp.ClientSession(connector=conn) as session:
        datas = await fetch_multi(session, urls)
        print(datas)

if __name__ == '__main__':
    asyncio.run(main())


2022-05-03 http , aiohttp , python , aio , async

使用 lux 下载哔哩哔哩视频

Lux 是一个使用 Go 语言编写的视频下载命令行工具,支持的平台很多,提供了包括 macOS、Windows、Linux 等等平台的命令行支持,安装和使用非常简单的。Lux 原来的名字是叫做 Annie(安妮),对标的是 macOS 上一款非常著名的视频下载软件叫做 [[Downie]](唐尼)荔枝数码正版授权。但后来改名成了 Lux。

Lux 支持非常多的视频网站:抖音、哔哩哔哩、半次元、pixivision、优酷、YouTube、爱奇艺、芒果 TV、Tumblr、Vimeo、Facebook、斗鱼视频、秒拍、新浪微博、Instagram、Twitter、腾讯视频、网易云音乐、音悦台

项目地址:https://github.com/iawia002/lux

Installation

macOS 下:

brew install ffmpeg
brew install lux

或者从 Release 页面下载,手动安装。

curl "https://github.com/iawia002/lux/releases/download/v0.15.0/lux_0.15.0_macOS_64-bit.tar.gz"

Ubuntu 下安装

sudo apt install ffmpeg
wget "https://github.com/iawia002/lux/releases/download/v0.15.0/lux_0.15.0_Linux_64-bit.tar.gz"
tar zxvf lux_0.14.0_Linux_64-bit.tar.gz
sudo mv lux /usr/local/bin
lux --help

使用

直接下载

Lux 的使用很简单,在终端:

lux "https://www.youtube.com/watch?v=QJXPS0gQ6Eg"
lux "https://www.bilibili.com/video/BV1ZJ411h713"

视频链接给的是播放列表里的第二个视频。如果用 youtube-dl 下载会自作主张地下载播放列表的第一个视频。在对付 B 站播放列表方面,Annie 比较乖一点。

Annie 不仅可以下载视频,如果给的是图片的网址,它就下载图片。

给播放列表的链接就下载播放列表:

下载不同分辨率

首先使用 -i 参数查看可供下载的视频分辨率,-i 参数可以一次添加多个视频链接,空格分隔。

❯ lux -i "https://www.bilibili.com/video/BV1ZJ411h713"

 Site:      哔哩哔哩 bilibili.com
 Title:     【中字】金世正 talk演唱会 全场 非常治愈的谈话
 Type:      video
 Streams:   # All available quality
     [64-7]  -------------------
     Quality:         高清 720P avc1.640028
     Size:            122.36 MiB (128300684 Bytes)
     # download with: lux -f 64-7 ...

     [32-12]  -------------------
     Quality:         清晰 480P hev1.1.6.L120.90
     Size:            108.75 MiB (114028043 Bytes)
     # download with: lux -f 32-12 ...

     [64-12]  -------------------
     Quality:         高清 720P hev1.1.6.L120.90
     Size:            108.57 MiB (113847391 Bytes)
     # download with: lux -f 64-12 ...

     [16-7]  -------------------
     Quality:         流畅 360P avc1.64001E
     Size:            86.10 MiB (90287066 Bytes)
     # download with: lux -f 16-7 ...

     [32-7]  -------------------
     Quality:         清晰 480P avc1.64001F
     Size:            67.43 MiB (70708693 Bytes)
     # download with: lux -f 32-7 ...

     [16-12]  -------------------
     Quality:         流畅 360P hev1.1.6.L120.90
     Size:            67.40 MiB (70670783 Bytes)
     # download with: lux -f 16-12 ...

然后使用 -f 来指定要下载的分辨率:

lux -f 64-7 https://www.bilibili.com/video/BV1ZJ411h713

下载列表

使用 -p 来下载视频列表。

如果要指定列表中的位置,可以使用如下几个选项:

  • -start 从视频列表的第几个开始下
  • -end 下载到几个
  • -items 指定要下载哪几个,比如 1,5,6,8-10
  • -eto B 站独有的参数,用于没有标题只有文件名的播放列表

举例:

lux -p -start 1 -end 15 "https://www.bilibili.com/video/BV1no4y1C7oo"

从文件中读取下载链接

可以使用 -F 参数,从包含视频 URL 的文本文件中下载视频:

lux -F /path/to/links.txt

这里也可以用参数 -start-end-items

按住 ctrl+c 可以中断下载,可以续传。

B 站上可以用 av 和 ep 加数字下载视频,比如:

annie -i ep198381 av21877586

还有三个参数也很有用:

指定保存路径

可以使用 -o 参数后面接路径,来指定将视频保存到该路径下:

lux -o ~/Videos/ URL

使用 -O NAME 来指定输出的名字。

输出 JSON

可以使用 -j 输出 JSON 格式结果。

  • 最出名的 [[youtube-dl]] 还有升级版的 [[yt-dlp]]
  • 适配比较多国内的 [[视频下载工具 you-get]]
  • Go 语言写的视频下载命令行工具 [[lux]]
  • C# 编写的 B 站下载 BBDown

2022-05-01 lux , bilibili , annie , video , 视频下载

Tailscale 简单使用

Tailscale 是一种用于构建安全、私有的网络的软件工具,可以在不同设备之间创建虚拟专用网络(VPN),并允许这些设备之间的安全通信。与传统的 VPN 不同,Tailscale 不需要使用 IP 地址或端口转发来实现网络连接。相反,Tailscale 使用每个设备上的唯一身份验证密钥来实现点对点的直接连接,从而提供了更高的安全性和便捷性。Tailscale 使用更高级的 [[WireGuard]] 协议来进行节点和节点之间的通信。

Tailscale 可以在多种操作系统和设备上使用,包括 Windows、macOS、Linux、iOS、Android 和路由器等。它还提供了许多其他功能,如内网穿透、跨设备的文件共享、远程访问和身份验证等,可以帮助用户更轻松地管理和连接其设备和网络。

在接触到 Tailscale 之前,也用过一段时间的 ZeroTierOmniEdge ,ZeroTier 其实到现在未知还一直在用,但是在中国大陆的速度确实不是很快,大部分的时间我只能连个 SSH 查看一下,其他的网络访问都比较慢,并且还丢包。OminiEdge 则是感觉安装的方式还略微有点麻烦,不如现在要介绍的 Tailscale 方便,并且 Tailscale 还有对应的 Ansible Playbook,我配置好之后基本上,如果有新节点的加入只需要跑一下 [[Ansible]] 即可。

Install

Debian/Ubuntu 下安装:

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/bionic.gpg | sudo apt-key add -
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/bionic.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update && sudo apt install tailscale

启动:

sudo tailscale up

查看 Tailscale IP 地址:

ip addr show tailscale0

或者

tailscale ip -4

需要注意的是目前是没有方法自定义 Tailscale 分配的 IP 地址。如果想要改变被分配的 IP 地址,可以通过如下方式强制分配新的:

ACL

Tailscale ACL(Access Control List),访问控制列表,可以严格限制特定用户或设备在 Tailscale 网络上访问的内容。

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 Tailscale/Headscale 默认会使用 allowall 访问策略进行初始化,该策略允许加入到 Tailscale 网络的所有设备之间可以相互访问。

Tailscale/Headscale 通过使用 group 这种概念,可以只用非常少的规则就能表达大部分安全策略。除了 group 之外,还可以为设备打 tag 来进一步扩展访问策略。结合 group 和 tag 就可以构建出强大的基于角色的访问控制(RBAC)策略。

Tailscale 的访问控制权限借鉴了 [[RBAC]] 基于角色的访问控制。

Headscale 的 ACL 策略主要包含以下几个部分:

  • acls:ACL 策略定义。
  • groups:用户的集合。Tailscale 官方控制器的“用户”指的是登录名,必须是邮箱格式。而  Headscale 的用户就是 namesapce
  • hosts:定义 IP 地址或者 CIDR 的别名。
  • tagOwners:指定哪些用户有权限给设备打 tag。
  • autoApprovers:允许哪些用户不需要控制端确认就可以宣告 Subnet 路由和 Exit Node。

ACL 规则

acls 部分是 ACL 规则主体,每个规则都是一个 HuJSON 对象,它授予从一组访问来源到一组访问目标的访问权限。

所有的 ACL 规则最终表示的都是允许从特定源 IP 地址到特定目标 IP 地址和端口的流量。虽然可以直接使用 IP 地址来编写 ACL 规则,但为了可读性以及方便维护,建议使用用户、Group 以及 tag 来编写规则,Tailscale 最终会将其转换为具体的 IP 地址和端口。

每一个 ACL 访问规则长这个样子:

  - action: accept
    src:
      - xxx
      - xxx
      - ...
    dst:
      - xxx
      - xxx
      - ...
    proto: protocol # 可选参数

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 ACL 规则中的 action 值一般都写 accept,毕竟默认是 deny 嘛。

src 字段表示访问来源列表,该字段可以填的值都在这个表格里:

高级功能

  • route 功能,通过虚拟路由实现通过一个节点访问到节点所在局域网内的所有内网设备
  • [[Tailscale Exit Nodes]] 出口节点功能实现设备的异地出口访问,让设备通过指定的节点作为出口

reference

  • [[2018-06-14-zerotier]]
  • [[2021-11-29-omniedge-usage]]

2022-04-28 tailscale , vpn , virtual-networks , linux , ubuntu

图片压缩工具 Squoosh 离线版

Squoosh 是 Google 推出的一个图片压缩工具。之前整理macOS 初始化设置 的时候就说过,基本上算是必不可少的一个压缩工具了。

如果要大批量压缩图片,之前也介绍过 jpegoptim 和 optipng

如果要实现更加高阶的图片操作,比如 resize, blur, crop, despeckle, dither, drow on, flip, join, re-sample 等等,也可以了解一下 [[ImageMagick]]。

但使用 Squoosh 的过程中有一点不方便的就是 Google 只提供了在线版,之前也在 issue 中提过,官方回复是本来这个工具就是命令行的一个在线化,没有必要再搞一个离线的版本。

但最近发现 GitHub 上有人做出了一个离线版本的 Squoosh。

离线版本的 Squoosh 基于 Electron,并使用了 GoogleChromeLabs 之前开源的在线版。

如果是在 macOS 下

macOS 有一个内置的图片压缩命令

sips -s formatOptions high path/*.jpg

2022-04-28 macos , linux , application , squoosh , google , electron , google-chrome , image , image-compress

电子书

本站提供服务

最近文章

  • Dinox 又一款 AI 语音实时转录工具 前两天介绍过 [[Voicenotes]],也是一款 AI 转录文字的笔记软件,之前在调查 Voicenotes 的时候就留意到了 Dinox,因为是在小红书留意到的,所以猜测应该是国内的某位独立开发者的作品,整个应用使用起来也比较舒服,但相较于 Voicenotes,Dinox 更偏向于一个手机端的笔记软件,因为他整体的设计中没有将语音作为首选,用户也可以添加文字的笔记,反而在 Voicenotes 中,语音作为了所有笔记的首选,当然 Voicenotes 也可以自己编辑笔记,但是语音是它的核心。
  • 音流:一款支持 Navidrom 兼容 Subsonic 的跨平台音乐播放器 之前一篇文章介绍了Navidrome,搭建了一个自己在线音乐流媒体库,把我本地通过 [[Syncthing]] 同步的 80 G 音乐导入了。自己也尝试了 Navidrome 官网列出的 Subsonic 兼容客户端 [[substreamer]],以及 macOS 上面的 [[Sonixd]],体验都还不错。但是在了解的过程中又发现了一款中文名叫做「音流」(英文 Stream Music)的应用,初步体验了一下感觉还不错,所以分享出来。
  • 泰国 DTV 数字游民签证 泰国一直是 [[Digital Nomad]] 数字游民青睐的选择地,尤其是清迈以其优美的自然环境、低廉的生活成本和友好的社区氛围而闻名。许多数字游民选择在泰国清迈定居,可以在清迈租用廉价的公寓或民宿,享受美食和文化,并与其他数字游民分享经验和资源。
  • VoceChat 一款可以自托管的在线聊天室 VoceChat 是一款使用 Rust(后端),React(前端),Flutter(移动端)开发的,开源,支持独立部署的在线聊天服务。VoceChat 非常轻量,后端服务只有 15MB 的大小,打包的 Docker 镜像文件也只有 61 MB,VoceChat 可部署在任何的服务器上。
  • 结合了 Google 和 AI 的对话搜索引擎:Perplexity AI 在日本,因为 SoftBank 和 Perplexity AI 开展了合作 ,所以最近大量的使用 Perplexity ,这一篇文章就总结一下 Perplexity 的优势和使用技巧。