uPic 是一个 macOS 上的图片上传工具,使用 Swift 编写。支持对接非常多的对象存储,以及可以自定义使用 [[Chevereto]],或者 Lsky Pro 作为图床。
可以直接从 App Store 安装,或者:
brew install bigwig-club/brew/upic --cask
Lsky Pro 兰空图床是一个 PHP 编写的图床程序。Lsky Pro 升级了 2.0 版本,API 接口也进行了重写。
首先使用用户名,密码获取 Token:
curl -X POST -F "email=email@address" -F "password=your_passwd" https://your.domain/api/v1/tokens
复制返回值中的 token 字段。
然后配置 uPic,创建一个自定义 Host:
POST /api/v1/upload
file
["data", "links", "url"]
示意图:
然后配置 Other fields,添加 Header,记得 Bearer 后面添加上面获取的 Token。
根据 Chevereto 的官方文档,可以配置:
API:
POST http://mysite.com/api/1/upload/?key=12345&source=http://somewebsite/someimage.jpg&format=json
参数:
key
, The API v1 key, can be found in admin dashboard.action
, 值是 upload
source
, URL 或者是图片的 Base64format
, 返回类型,可以是 json
, redirect
, txt
返回结果
{
"status_code": 200,
"success": {
"message": "image uploaded",
"code": 200
},
"image": {
"name": "example",
"extension": "png",
"size": 53237,
"width": 1151,
"height": 898,
"date": "2014-06-04 15:32:33",
"date_gmt": "2014-06-04 19:32:33",
"storage_id": null,
"description": null,
"nsfw": "0",
"md5": "c684350d722c956c362ab70299735830",
"storage": "datefolder",
"original_filename": "example.png",
"original_exifdata": null,
"views": "0",
"id_encoded": "L",
"filename": "example.png",
"ratio": 1.2817371937639,
"size_formatted": "52 KB",
"mime": "image/png",
"bits": 8,
"channels": null,
"url": "http://127.0.0.1/images/2014/06/04/example.png",
"url_viewer": "http://127.0.0.1/image/L",
"thumb": {
"filename": "example.th.png",
"name": "example.th",
"width": 160,
"height": 160,
"ratio": 1,
"size": 17848,
"size_formatted": "17.4 KB",
"mime": "image/png",
"extension": "png",
"bits": 8,
"channels": null,
"url": "http://127.0.0.1/images/2014/06/04/example.th.png"
},
"medium": {
"filename": "example.md.png",
"name": "example.md",
"width": 500,
"height": 390,
"ratio": 1.2820512820513,
"size": 104448,
"size_formatted": "102 KB",
"mime": "image/png",
"extension": "png",
"bits": 8,
"channels": null,
"url": "http://127.0.0.1/images/2014/06/04/example.md.png"
},
"views_label": "views",
"display_url": "http://127.0.0.1/images/2014/06/04/example.md.png",
"how_long_ago": "moments ago"
},
"status_txt": "OK"
}
[[Backblaze B2 Cloud Storage]]
同类的图片上传工具还有:
很早以前就收到 GitHub 邮件说可以使用 Codespaces Beta 了。但当时没有怎么在意,最近在想要修改一些项目中个别配置的时候不想将整个项目都拉到本地然后再提交,就尝试了一下网页端的 Codespaces,没想到的是整个体验过程非常顺畅,并且自动同步了之前在 VSCode 上的所有配置。
点击下图中的 Create codespace 可以快速地创建。
默认会使用 4 核 8G 内存 32 GB 磁盘的 Codespaces。
GitHub Codespaces 已经正式发布了,免费的用户也可以拥有一个 2 核 15GB 空间,一个月 60 分钟的 Space 空间。如果选择 4 核的空间,相应的就只能免费使用 30 分钟;选择 8 核的空间就只能免费使用 15 分钟。
默认的 Codespaces 包括了常用的工具,包括 Python,Node.js,Docker 等等。1 如果要使用自定义的镜像,那么可以参考 这里
GitHub Codespaces 提供了一个在线的编程环境,GitHub 会创建一个在线的 Codespace,一个虚拟的容器。用户可以直接在浏览器中,或者通过本地的 Visual Studio Code 远程连接到该 Space,直接进行文件的修改。
用户所有创建的 Codespaces 都可以在这里 找到。
这篇笔记新建的时间是 2020 年 12 月 29 号,想来从那个时间点开始我就一直想着怎么离开豆瓣了。过去一年时间里面陆陆续续也发现了不少不错的网站,甚至有一些比豆瓣都要好用。这里就再整理一下。
豆瓣让我不能忍受的便是对词条的删减,以及对用户笔记,影评,书评的肆意审查,基本导致了现在豆瓣陷入不可用的状态。
我也曾经说过,我离不开豆瓣的几个理由:
NeoDB 是一个建立在 federated network (联邦网络)中的用来标记书籍、电影、音乐和游戏的网站。
NeoDB 目前只能通过 [[Mastodon]] (或[[Pleroma]]/Friendica/PixelFed)实例的账号来登录。
我的页面:https://neodb.social/users/einverne@m.einverne.info/
themoviedb 简称为 TMDB ,是一个从 2008 年开始的电影,剧集数据库。拥有非常全的数据库。
TMDB 也开放了编辑入口,所有的注册用户都可以贡献,和当年的豆瓣非常相似,官方也有非常详细的 贡献指南 。
看网站的设计,词条的界面,数据也非常详细,设计也不错。
[[trakt]] 是一个电视剧和电影媒体资源订阅追踪平台,电视界的 IMDB。可以认为是一个电视剧的数据库,有每个电视剧的元数据,至少包括剧名、首播时间、是否完结、长度、季、集、语言、国家、简介、类别、演员,链接到官网,IMDB,TMDB,TVDB,Wiki 等的链接等等。而且这些数据是公开的,有非常多 App 在使用他作为基础数据提供其他服务。
Trakt 相较于豆瓣更好的地方在于可以和第三方的应用交互,比如在 Plex 中看完一集之后可以自动同步到 trake。
Trakt 还支持 [[Kodi]], [[Plex]], [[Emby]], [[Netflix]], [[Infuse]], [[Jellyfin]], [[MediaPortal]], [[MrMC]], [[Stremio]], [[Serviio]], [[VLC]] 等等。
Trakt 还提供了 VIP 增值服务,包括了如上的功能。个人 30$ 一年起步,还有另外一个是 60$ 一年。
LitterBoxd 是另一个可以标记看过电影的网站。不过 LetterBoxd 只支持电影。
首页:
词条页面
TBDB 是专注在剧集的网站。
IMDB 就不用多说了,老牌的电影资料站。
Google Book 的 API 文档:
Amazon 收购而来的网站,和 Kindle 搭配使用。
可以用来追踪阅读进度,以及管理看过书籍。
本人不怎么使用豆瓣音乐,所以没怎么整理,不过 Last.FM 已经存在很多年了。数据也比较全。
之前在 Proxmox 上给 Ubuntu 划分了 64GB 的空间,运行一段时间之后磁盘空间剩余不多,就抽时间扩展一下。本文就记录一下给 Proxmox VE 的虚拟机扩展的过程。其实之前的文章里面也略微提到过一些,但是没有完整记录。
本来想着是这一篇文章把虚拟机的扩展和缩减空间一并整理了,但写着写着篇幅就比较大了,本文最后还是集中在扩容部分,缩减(shrink) 部分有机会再整理吧。
在扩容之前,为了防止发生错误,请先备份虚拟机,然后关闭虚拟机操作。
关于备份的操作可以参考: Proxmox VE 下备份和恢复虚拟机
在 Proxmox VE 管理后台,点击虚拟机,在 Hardware 中选中 Hard Disk,然后在菜单栏中就能看到 Resize 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
属于 [[20220417-21 天计划]] 的第3本书。
[[现代性]]是指的现代社会所具有的一些典型特征。现代(modern)一词16世纪才被创造出来。字面上的含义是「当下或此刻」。人们有了时间的概念,生活不再周而往复。
这本书中对现代性的解释大致分为两个层面:
官僚体制中的人摆脱了道德上的谴责。 冷静、高效、专业的完成自己的工作。
为什么这些正常人能摆脱道德上的自责呢?
犹太人是受害者,但鲍曼说犹太人也负有责任,是大屠杀的帮凶,这些犹太人受到理性的驱动。而理性也是现代性的一个特征。
鲍曼在这本书中提出了一个骇人听闻的观点:「德国纳粹在二战期间实行的对犹太人的种族灭绝是现代性的表现」。
现代官僚制度和现代技术还让屠杀犹太人的纳粹分子在执行任务时摆脱了道德上的困扰。
道德,对他人无条件的责任
现代性体制会压制道德,现代官僚体系会让技术责任代替道德责任,现代社会的原子化倾向会让人们成为互相隔离的冷漠个体。但正因为如此,才更需要重视道德,在任何情况下,一个人都要承担其自己的道德责任,不管发生什么,他都应该去做对的事情。这是避免下一次大屠杀发生的唯一方式。
一直想学习一下视频剪辑,这两天正好拿一个韩剧试一下,但没想到第一步导入就被拦在了外面,不过还好,正好可以学习一下 mkv 格式,以及基本的视频格式。
我在将 mkv 格式的文件导入到 Adobe Premiere 的时候报错:
File format not supported.
mkv 的全称是 Matroska Video File,是一种开放的多媒体档案封装格式,可以将不同编码的影片,音轨,字幕封装到同一个档案中。通常的扩展名是 .mkv
, .mka
, .mks
等等。1
Adobe 从 2019.1.5 版本开始就放弃支持 mkv 格式了2。
本质上 mkv 是一个封装格式,Adobe Premiere 还是支持编辑其中封装的视频内容的。
首先安装 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 标准制定的目的就是为了创建一个更好的视频压缩标准,可以在更低的比特率的情况下可以提供更好的视频质量。
Go 语言中常见的容器。
var name [size]T
举例:
var classMates [3]string
# or
classMates2 := [...]string{"A", "B", "C"}
切片是对数组的一个连续片段的引用,容量可变的序列。动态数组。
内部结构包括底层数组指针、大小和容量。
从原数组中生成一个切片:
slice := source[begin:end]
举例:
source := [...]int{1,2,3}
sli := source[0:1]
动态创建切片,可以通过 make
函数动态创建切片
make([]T, size, cap)
直接声明新的切片,不需要指定大小:
var name []T
比如:
ex := []int{1,2,3}
append
函数可以向切片添加元素,返回新的切片。
复制切片内容
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)
}
前端时间给 Proxmox VE 下的虚拟机扩容的时候留意到了这个 growpart 命令,专门用来给分区进行扩容的命令。
growpart - extend a partition in a partition table to fill available space
growpart 工具完成 Linux 系统盘分区扩容及文件系统扩展
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
分区是磁盘的最后一个分区,如果你要扩容的分区在分区中间,可能需要考虑其他方案。
最近想找一个 [[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(协程)是一个更通用的 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 密集型任务:
安装使用:
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 是一个线程计数器,核心是 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()
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())
Lux 是一个使用 Go 语言编写的视频下载命令行工具,支持的平台很多,提供了包括 macOS、Windows、Linux 等等平台的命令行支持,安装和使用非常简单的。Lux 原来的名字是叫做 Annie(安妮),对标的是 macOS 上一款非常著名的视频下载软件叫做 [[Downie]](唐尼)荔枝数码正版授权。但后来改名成了 Lux。
Lux 支持非常多的视频网站:抖音、哔哩哔哩、半次元、pixivision、优酷、YouTube、爱奇艺、芒果 TV、Tumblr、Vimeo、Facebook、斗鱼视频、秒拍、新浪微博、Instagram、Twitter、腾讯视频、网易云音乐、音悦台
项目地址:https://github.com/iawia002/lux
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"
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
来指定输出的名字。
可以使用 -j
输出 JSON 格式结果。