替代群晖相册的工具:immich

一直以来,我都用群晖自带的 Photos 来备份手机照片,因为除了群晖相册之外,还没用过其他好用的相册工具,自从上次群晖文件系统都变成只读之后就有了用Ubuntu替换群晖的想法。然后就在网络中发现了Immich,immich有Android手机客户端,可以直接从f-droid安装。

官方部署教程

下面简要记录部署教程:

下载安装部署必要文件

我们使用docker-compose部署,首先创建一个存储docker-compose.yml.env 文件的目录.

1
2
mkdir ./immich-app
cd ./immich-app

下载docker-compose.ymlexample.env文件

下载docker-compose.yml文件

1
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml

下载.env文件

1
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

或者用浏览器下载这两个文件,然后放到刚刚创建的目录中。

Note: If you downloaded the files from your browser, also ensure that you rename example.env to .env.

修改.env文件中的变量值

  • Populate custom database information if necessary.
  • UPLOAD_LOCATION 设置成你的照片存储路径.
  • DB_PASSWORD 设置数据库的密码
  • TYPESENSE_API_KEY 设置成随机字符串。

可以修改docker-compose.yml文件,在Postgres数据库那里增加5432端口映射,把Postgres容器的5432端口映射到本地,这样后期本地安装应用的时候可以用到docker的数据库。

创建容器

From the directory you created in Step 1, (which should now contain your customized docker-compose.yml and .env files) run docker-compose up -d.

Start the containers using docker compose command

1
docker-compose up -d     # or `docker compose up -d` based on your docker-compose version

现在可以访问http://<machine-ip-address>:2283开始创建你的管理员账户了。

设置Nginx反向代理

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
server {
listen 618 default_server;
listen [::]:618 default_server;

# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;

#root /var/www/start;

# Add index.php to the list if you are using PHP
#index index.html index.htm index.nginx-debian.html;

server_name www.redtux.cn;

client_max_body_size 50000M;

location / {
proxy_pass http://127.0.0.1:2283;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# http://nginx.org/en/docs/http/websocket.html
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
}

升级

Immich的版本迭代速度相当快,如果有新版本发布,可以切换到docker-compose.yml文件存放到目录,然后执行如下命令:

1
docker-compose pull && docker-compose up -d     # Or `docker compose up -d`

备份数据库

The recommended way to backup and restore the Immich database is to use the pg_dumpall command.

备份

1
docker exec -t immich_postgres pg_dumpall -c -U postgres | gzip > "/path/to/backup/dump.sql.gz"

恢复

1
2
3
4
5
6
7
docker-compose down -v  # CAUTION! Deletes all Immich data to start from scratch.
docker-compose pull # Update to latest version of Immich (if desired)
docker-compose create # Create Docker containers for Immich apps without running them.
docker start immich_postgres # Start Postgres server
sleep 10 # Wait for Postgres server to start up
gunzip < "/path/to/backup/dump.sql.gz" | docker exec -i immich_postgres psql -U postgres -d immich # Restore Backup
docker-compose up -d # Start remainder of Immich apps

桌面系统上传工具

依赖 Node.js 16以上版本和npm

安装node.js后执行如下命令安装immich桌面端上传工具:

1
npm i -g immich

把本地目录~/toUpload中的照片上传到服务器:

1
immich upload --key sikjo7P3o5jLddv3pfiDjH3RVfj4yIuptOti8SetM --server http://192.168.0.6:2283/api --recursive ~/toUpload

把本地目录~/toUpload中的照片上传到服务器,并加入到AlbumName相册中:

1
immich upload --key sikjo7P3o5jLddv3pfiDjH3RVfj4yIuptOti8SetM --server http://192.168.0.6:2283/api --recursive --album AlbumName ~/toUpload

选项:

Parameter Description
–yes / -y Assume yes on all interactive prompts
–recursive / -r Include subfolders
–delete / -da Delete local assets after upload
–key / -k User’s API key
–server / -s Immich’s server address
–threads / -t Number of threads to use (Default 5)
–album/ -al Create albums for assets based on the parent folder or a given name
–import/ -i Import gallery (assets are not uploaded)

号外

还有一个相册工具 PhotoPrism,这是一个优秀的成熟的相册,唯一缺憾就是没有手机客户端。

安装可道云Kodexplorer

可道云Kodexplorer是一个基于web的文件管理器,这里可以查看官方文档

nginx配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 620 default_server;
listen [::]:620 default_server;

root /var/www/kodexplorer;
index index.php
server_name www.redtux.cn;

location / {
try_files $uri $uri/ =404;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
# fastcgi_pass 127.0.0.1:9000;
}

location ~ /\.ht {
deny all;
}
}

php库缺失 curl
php库缺失 mb_string
须开启php GD库,否则验证码、缩略图使用将不正常

配置优化

  1. 修改nginx的配置文件
1
2
3
4
5
6
7
8
client_max_body_size 500M;        
client_header_timeout 3600s;
client_body_timeout 3600s;
fastcgi_connect_timeout 3600s;
fastcgi_send_timeout 3600s;
fastcgi_read_timeout 3600s;
# 其他webserver相应修改类似限制;如apache需要修改LimitRequestBody
# 修改完成重启nginx生效: service nginx reload
  1. 修改php配置文件php.ini;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
post_max_size = 500M;
upload_max_filesize = 500M;
memory_limit = 500M;
max_execution_time = 3600;
max_input_time = 3600;

# php中设置set_time_limit无效(safe_mode=on时php代码中修改超时无效) php.ini
safe_mode = off

# php-fpm.conf 配置优化(超时时间; 4G内存推荐如下子进程配置)
request_terminate_timeout 3600
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 30
pm.max_requests = 500
  • 注意:
    • 如果某一类例如exe文件不能上传,其他文件可上传, 一般是服务器(杀毒软件或防火墙)做了拦截误判,取消相应软件上拦截即可;
    • 超时时间设置; 如果经常有超大文件上传,php和nginx超时时间需要设置大一些;
    • 分片上传: 一个大文件切分成多个分片上传,所有片上传完成后服务器自动合并;一个分片上传失败只需要重传该分片即可;
    • 分片大小设置: 管理员登陆后台–基础设置–上传下载; 调整上传分片大小; 必须小于php.ini和nginx的限制;
    • 修改了php或nginx配置文件后,需要重启php-fpm和nginx;
    • 上传文件限制及超时时间可以根据自己需求设置; 超时时间需大于文件上传下载的时间,否则超时会导致操作失败;
  1. 修改可道云配置

设置方法:管理员登陆可道云进入后台 系统设置—基础设置—上传/下载

  • 设置分片大小: 推荐5M

大文件上传时切分成片进行并发上传,从而实现加速和断点续传,
推荐5M; 此值必须小于下述配置;否则会引起上传异常(上传失败,进度回退)
php.ini: post_max_size, upload_max_filesize ==> 5M
nginx: client_max_body_size ==> 5M;

  • 上传并发数量; 推荐15个并发;
  1. nginx + php-fpm上传优化

在nginx.conf中添加如下代码,参考更多nginx优化

1
2
3
4
#使用共享内存做临时存贮提高上传速度,共享内存需要大一些,否则上传大文件内存不足
client_body_in_file_only clean;
client_body_temp_path /dev/shm 1 2;
fastcgi_param REQUEST_BODY_FILE $request_body_file;

安装docker及docker-compose

卸载旧版本

在你安装docker之前一定要把系统中的旧版本卸载掉,一半系统发行商在官方apt源中带有docker,但是不是最新版的,如果你是全新安装的系统,你还没有安装过docker,那就可以省掉这一步。

需要卸载掉的非官方包包括:

  • docker.io
  • docker-compose
  • docker-doc
  • podman-docker

运行如下命令卸载这些包:

1
$for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

apt-get 可能会提示你这些包没有安装。

Images, containers, volumes, and networks 存储在 /var/lib/docker/ 目录中不会自动删除,如果你想要一个全新安装的docker,你最好手动删除他们。

安装途径

你可以根据你的需要使用如下方法安装docker:

  • 安装docker桌面版,桌面版包含了docker,这是最简单最快捷的方法;

  • 从Docker的官方apt库安装;

  • 自己手动安装;

  • 用脚本自动安装,只推荐用在测试和开发环境中。

从Docker的官方apt库安装

在新装系统第一次安装Docker之前,首先要设置Docker的官方apt库,设置apt库之后就可以使用apt命令安装了。

设置Docker的官方apt库

按照如下命令,安装一些工具和允许使用https协议:

1
2
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

添加Docker的官方GPG key:

1
2
3
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

按照如下命令设置Docker的官方apt库:

1
2
3
4
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

注意

If you use an Ubuntu derivative distro, such as Linux Mint, you may need to use UBUNTU_CODENAME instead of VERSION_CODENAME.

更新包索引:

1
sudo apt-get update

安装 Docker Engine

运行如下命令安装最新版Docker:

1
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

如果要安装特定版本Docker,可以先用如下命令列出可用版本:

1
2
# List the available versions:
$ apt-cache madison docker-ce | awk '{ print $3 }'

返回可用的版本号:

1
2
3
5:24.0.0-1~ubuntu.22.04~jammy
5:23.0.6-1~ubuntu.22.04~jammy
<...>

选择你期望的版本进行安装:

1
2
VERSION_STRING=5:24.0.0-1~ubuntu.22.04~jammy
sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin

运行一下 hello-world 镜像验证Docker是否安装成功。

1
sudo docker run hello-world

这条命令会下载hello-world镜像,并在一个新建的容器中运行。

到此Docker就已经安装成功了。

安装 docker-compose

上面已经安装了docker compose插件,可以通过docker compose命令运行,就是版本会旧一些,最新版的可以去docker-compose的Github下载二进制文件,然后复制到PATH路径中。

卸载 Docker Engine

1.Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

1
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

2.Images, containers, volumes, or custom configuration files on your host aren’t automatically removed. To delete all images, containers, and volumes:

1
2
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

You have to delete any edited configuration files manually.

Docker服务控制

停止Docker服务

1
systemctl stop docker

启动Docker服务

1
systemctl start docker

重新启动Docker服务

1
systemctl restart docker

Docker常用命令

  • docker start : 启动一个容器
  • docker restart : 重新启动一个容器
  • docker stop : 关闭一个容器
  • docker status : 查看docker运行状态
  • docker ps : 列出正在运行的容器
  • docker volume : 新建docker卷
  • docker run : 从一个镜像放在新建的容器中运行。

其他详细命令可以参考官方文档

其他特定命令:

获取容器ID为282c7625119d的ip

1
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 282c7625119d

启动所有容器:

1
docker start $(docker ps -aq) 

关闭所有容器:

1
docker stop $(docker ps -aq) 

创建时设置容器开机自启:

1
docker run -d --restart=always -name 容器名 使用镜像

修改已有容器开机自启:

1
2
docker update --restart=always 容器ID(或者容器名)
(容器ID或者容器名根据实际情况修改)

对已有docker容器增加新的端口映射

1、 docker ps -a #查看容器的信息

2、 docker port 容器ID/容器名称 #查看容器的端口映射情况

3、 docker inspect 容器ID |grep Id #查找要修改容器的全ID

4、 cd /var/lib/docker/containers/全ID #进到全Id相同的目录,修改 其中的hostconfig.json 和 config.v2.json文件: #注意:若该容器还在运行中,需要先停掉 docker stop 容器ID #再停掉docker服务 systemctl stop docker

5、修改hostconfig.json如下 # 格式如:”{容器内部端口}/tcp”:[{“HostIp”:””,”HostPort”:”映射的宿主机端口”}]
“PortBindings”:{“22/tcp”:[{“HostIp”:””,”HostPort”:”3316”}],”80/tcp”:[{“HostIp”:””,”HostPort”:”180”}]}

{“5432/tcp”:[{“HostIp”:””,”HostPort”:”5432”}]}

6、修改config.v2.json在ExposedPorts中加上要暴露的端口 # 格式如:”{容器内部端口}/tcp”:{} “ExposedPorts”:{“22/tcp”:{},”80/tcp”:{}}

{“5432/tcp”:{}}

修改docker镜像源

镜像源参考
中国区官方镜像:https://registry.docker-cn.com
中科大源:https://docker.mirrors.ustc.edu.cn
阿里源:https://cr.console.aliyun.com
腾讯源:https://mirror.ccs.tencentyun.com
网易源:http://hub-mirror.c.163.com

1、关闭 Docker 服务

2、修改配置文件

创建或修改/etc/docker/daemon.json文件,
默认没有daemon文件,先创建。

1
vim /etc/docker/daemon.json

增加/更新”registry-mirrors”字段

1
2
3
4
5
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn"
]
}

注:需确认”daemon.json”的位置。

3、重启 Docker 服务

删除系统自带的snap

snap list可以查看已经安装的包,默认带的组件是core、lxd、snapd。

删除一个snap包

1
sudo snap remove docker

卸载snap

1
sudo apt autoremove --purge snapd

这样就会连带snap安装的所有软件全部都卸载掉了。

安装Bind9用于本地域名解析

对于家里的移动客户端,在家的时候用Wi-Fi,在外的时候用的移动网,那我们希望在家用Wi-Fi的时候可以直接连内网ip,而不需要连公网ip再转发到Nas的内网ip。以前用小米路由器的时候可以自定义hosts,非常方便。群晖中有一个DNS Server套件可以实现域名直接解析到内网IP,Ubuntu中可以安装Bind9实现同样功能。

Bind9的官方Howto在这里

Bind9安装

1
2
sudo apt update
sudo apt install bind9

Bind9的配置文件位于/etc/bind/,主要配置文件为下面的三个:

1
2
3
/etc/bind/named.conf
/etc/bind/named.conf.options
/etc/bind/named.conf.local

配置转发DNS地址,就是当本地没有解析记录的,就转发到指定的DNS地址解析。编辑配置文件/etc/bind/named.conf.options,指定转发DNS,一般填大网络公司的公共DNS,谷歌8.8.8.8;阿里:223.5.5.5等:

1
2
3
4
5
6
7
8
[...]

forwarders {
8.8.8.8;
114.114.114.114;
};

[...]

现在Bind9就可以工作了,重启Bind9:

1
sudo service bind9 restart

现在就可以在路由器的DHCP设置中将DNS服务器地址设置为NAS的IP了。

接下来我们要编辑区域文件/etc/bind/named.conf.local,增加我们要解析的域名Zone:

1
2
3
4
5
6
7
8
[...]

zone "example.com" {
type master;
file "/etc/bind/db.example.com";
};

[...]

这一段记录example.com域名的解析文件为/etc/bind/db.example.com,接下来我们编辑/etc/bind/db.example.com/etc/bind目录中有一份样板文件db.local:

1
sudo cp /etc/bind/db.local /etc/bind/db.example.com

编辑区域文件/etc/bind/db.example.com,把localhost修改为你的域名example.com,保留后面的点,把127.0.0.1修改为本机IP,root.localhost. 修改为邮件地址,只不过要把@替换为.,同样末尾点保留。

增加一条A记录,把ns.example.com解析到DNS服务器IP,然后就可以添加其他子域名解析,比如我只有一台NAS,所有的记录都解析到NAS的IP上,修改完大概就是这样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
;
; BIND data file for local loopback interface
;
$TTL 604800
@ IN SOA ns.example.com. root.example.com. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS ns.example.com.
ns IN A 192.168.1.10

;also list other computers
www IN A 192.168.1.10
music IN A 192.168.1.10

这样内网访问www.example.commusic.example.com都会解析到192.168.1.10。

注意每次修改此文件,都需要把Serial值增加一次,这样重启的时候Bind9就会知道配置文件有修改。

很多人喜欢用修改日期来作为Serial的值,例如 2023080500,表示2023年8月5日第一次修改。

修改完成后记得重启bind9:

1
sudo service bind9 restart

这样移动设备连接内网的时候,从路由器获取的DNS服务器就是你的NAS地址,NAS就会把你的域名解析到NAS上。这样你就可以用一个域名根据网络环境自动切换内网和外网了。

当然,Bind9除了用来解析域名到局域网外,还可以用来解析某些被DNS劫持的域名,我们可以先去https://tools.ipip.net/dns.php,查询一下域名对应IP,再ping一下选一个延迟低丢包少的ip,然后配置bind9,把域名解析到查询到的ip上。

安装Samba用于本地文件分享

Samba安装

1
2
sudo apt update
sudo apt install samba

配置用户,为用户设置密码

1
sudo smbpasswd -a [user]

编辑配置文件

1
sudo vi /etc/samba/smb.conf

在配置文件末尾增加一段需要分享的目录设置

1
2
3
4
5
6
7
8
[ShareData]
comment = share folder
path = /path/data
available = yes
browseable = yes
writeable = yes
read only = no
valid users = [user]

[ShareData]是访问分享文件时显示的分享名称;path指向分享文件的真实路径;[user]为访问分享文件的用户名,跟上面设置密码时的用户名一致;这一段可以重复添加,有几处需要分享就可以添加几次,保证每个分享名称不一样就可以了。

重启Samba服务

1
sudo service smbd restart

接下来就可以从局域网其他客户端smb://IP访问分享的文件了。

Qt生成缩略图片存入sqlite

Qt生成缩略图片存入sqlite

新建一个工程pro文件中加入 QT += sql 添加sql支持。

>folded
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
// main.cpp

#include <QApplication>
#include <QtGui>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

//添加数据库,不表
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "conn1");
db.setDatabaseName("/home/htux/thumbs.sqlite");
if(!db.open()) return 1;

QByteArray baImage;

QString filename = "/home/htux/file2.jpg";
QPixmap pixmapIn(filename);

QBuffer buffer(&baImage);
buffer.open(QIODevice::WriteOnly);

QPixmap pixmapSmall;
//让生成的缩略图高宽都不超过256.
pixmapSmall = pixmapIn.scaled(256,256,
Qt::KeepAspectRatio, Qt::SmoothTransformation);
//保存生成的缩略图到ByteArray, 格式为JPG, 图片质量50.
//图片质量的取值Qt文档中没查到,不过按照国际惯例应该是0-100
//保存几个不同质量的图片看看差别
pixmapSmall.save(&buffer, "JPG",50);
pixmapSmall.save("/home/htux/file2.png", "PNG");
pixmapSmall.save("/home/htux/file2-5.jpg", "JPG", 20);
pixmapSmall.save("/home/htux/file2-5.jpg", "JPG", 50);
pixmapSmall.save("/home/htux/file2-8.jpg", "JPG", 80);

QSqlQuery query(db);

query.exec("CREATE TABLE thumbs "
"(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
" filename VCHAR(20) , thumbnail BLOB);");

QString sql = QString("INSERT INTO thumbs VALUES "
"( NULL , :filename, :thumbnail );");

query.prepare(sql);
query.bindValue(":filename", filename);
query.bindValue(":thumbnail", baImage);

query.exec();

query.exec("select * from thumbs;");

//跳到最后存入的记录
if (!query.last()) return 1;

QPixmap pixmapOut;
//读出存入的图片
pixmapOut.loadFromData(query.value(2).toByteArray());

db.close();
//把图片用Label显示出来.
QLabel label;
label.setPixmap(pixmapOut);
label.show();

return a.exec();
}

QLineEdit获取焦点后全选字符/失去焦点清除选择

一直觉得Chrome的地址栏的体验非常好,获取焦点后自动全选,无论是想复制地址还是重新输入新的地址都帮我们省掉了一步,如何用QLineEdit实现这个特点呢。

网上搜索了一下,发现一篇博客http://www.cnblogs.com/91program/p/5521420.html ,但是这篇博客讲述的方法有点复杂,最后还要通过延时来达到目的,有点怪异。

最后只得查看QLineEdit的类参考仿照Chrome实现,Chrome的地址栏在无焦点状态下鼠标按下不动的时候,地址栏获取了焦点,光标位于鼠标位置;鼠标无移动释放,全选地址栏字符;再次单击,清除全选;鼠标按下移动后释放,则不会全选,而是选择字符;地址栏失去焦点,清除选择。

看起来我们需要判断鼠标按下时的位置与鼠标释放时鼠标有没有移动,申请一个变量m_pressPos来存储鼠标按下时的位置。还需要知道鼠标单击的时候QLineEdit是否已获得焦点,我们用变量m_onFocus来记录。定义一个QLineEdit子类,然后重新实现mousePressEvent,mouseReleaseEvent,focusOutEvent。

代码如下:

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
#ifndef URLLINEEDIT_H
#define URLLINEEDIT_H

#include <QLineEdit>

class UrlLineEdit : public QLineEdit
{
Q_OBJECT
public:
UrlLineEdit(QWidget *parent = 0);
~UrlLineEdit();
protected:
void mouseReleaseEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void focusOutEvent( QFocusEvent * e );
private:
bool m_onFocus;
QPoint m_pressPos;
};
#endif // URLLINEEDIT_H

#include "urllineedit.h"
#include <QFocusEvent>

UrlLineEdit::UrlLineEdit(QWidget *parent)
:QLineEdit(parent),
m_onFocus(false)
{

}

UrlLineEdit::~UrlLineEdit()
{

}
void UrlLineEdit::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton ){
if( e->pos() == m_pressPos && !m_onFocus){
m_onFocus = true;
selectAll();
update();
} else {
int start = cursorPositionAt(m_pressPos);
setSelection( start , cursorPositionAt(e->pos())-start );
}
}
QLineEdit::mouseReleaseEvent(e);

}

void UrlLineEdit::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton){
m_pressPos = e->pos();
setCursorPosition(cursorPositionAt(m_pressPos));
}
QLineEdit::mousePressEvent(e);
}

void UrlLineEdit::focusOutEvent(QFocusEvent *e)
{
m_onFocus = false;
if(!hasSelectedText()){
deselect();
}
QLineEdit::focusOutEvent(e);
}

通过测试基本上是实现了类似Chrome的这个特性。

macOS系统使用技巧

1.tree命令

自定义

mac下默认是没有 tree命令的,不过我们可以使用find命令模拟出tree命令的效果,如显示当前目录的 tree 的命令:

1
$ find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'

当然你也可以写一个别名来快速执行该命令,运行如下命令,将上面这个命令写到~/.bash_profile里,以后直接运行tree命令就更方便了:

1
alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"

安装tree命令行工具

也可以使用 homebrew 安装 tree 命令行:brew install tree

这样就在你的mac上安装了 tree 命令行了。

tree命令行参数(只实用与安装了tree命令行工具):

  • -a 显示所有文件和目录。
  • -A 使用ASNI绘图字符显示树状图而非以ASCII字符组合。
  • -C 在文件和目录清单加上色彩,便于区分各种类型。
  • -d 显示目录名称而非内容。
  • -D 列出文件或目录的更改时间。
  • -f 在每个文件或目录之前,显示完整的相对路径名称。
  • -F 在执行文件,目录,Socket,符号连接,管道名称名称,各自加上”*”,”/“,”=”,”@”,”|”号。
  • -g 列出文件或目录的所属群组名称,没有对应的名称时,则显示群组识别码。
  • -i 不以阶梯状列出文件或目录名称。
  • -I 不显示符合范本样式的文件或目录名称。
  • -l 如遇到性质为符号连接的目录,直接列出该连接所指向的原始目录。
  • -n 不在文件和目录清单加上色彩。
  • -N 直接列出文件和目录名称,包括控制字符。
  • -p 列出权限标示。
  • -P 只显示符合范本样式的文件或目录名称。
  • -q 用”?”号取代控制字符,列出文件和目录名称。
  • -s 列出文件或目录大小。
  • -t 用文件和目录的更改时间排序。
  • -u 列出文件或目录的拥有者名称,没有对应的名称时,则显示用户识别码。
  • -x 将范围局限在现行的文件系统中,若指定目录下的某些子目录,其存放于另一个文件系统上,则将该子目录予以排除在寻找范围外。

2.改变APP图标

最近发现有些APP图标实在是难看,忍不住想换个标,就在网上查了下资料,MacOS系统提供了生成icns的命令,我们需要准备一张png的图,这张图最小要1024*1024的分辨率。

制作步骤:

  1. 找图
    找一张分辨率1024*1024的png图片

  2. 建图片集目录
    打开终端输入以下命令:
    mkdir xxx. iconset
    注意:必须以.iconset后缀结尾

  3. 转换图片
    把原图片转为不同大小的图片,并放入上面的创建的目录中
    sips -z 16 16 pic.png –out xxx.iconset/icon_16x16.png
    sips -z 32 32 pic.png –out xxx.iconset/icon_16x16@2x.png
    sips -z 32 32 pic.png –out xxx.iconset/icon_32x32.png
    sips -z 64 64 pic.png –out xxx.iconset/icon_32x32@2x.png
    sips -z 128 128 pic.png –out xxx.iconset/icon_128x128.png
    sips -z 256 256 pic.png –out xxx.iconset/icon_128x128@2x.png
    sips -z 256 256 pic.png –out xxx.iconset/icon_256x256.png
    sips -z 512 512 pic.png –out xxx.iconset/icon_256x256@2x.png
    sips -z 512 512 pic.png –out xxx.iconset/icon_512x512.png
    sips -z 1024 1024 pic.png –out xxx.iconset/icon_512x512@2x.png
    @2x 的是为retina屏准备的,以上命令执行完后去目录里看下图片是否生成好了

  4. 生成图标
    这一步就是制作icns的最后一步了
    在命令行中输入一下命令
    iconutil -c icns xxx.iconset -o xxx.icns
    这时,目录中就会出现你要的icns图标文件了

  5. 替换图标
    在应用程序中找到想要替换的APP,右键,显示简介,然后把刚才的icns文件拖到简介里就可以了,替换完了之后需要把APP退出后才能看到新的图标。

批量制作

可以把制作过程写成一个shell文件,保存成.sh文件,这样就可以批量生成不同大小的图片并执行iconutil命令

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
#!/bin/sh
if [ x"$1" = x ]; then
echo "\033[31m 请输入要转换的图片全名(PNG格式的图片) \033[0m"
exit
fi
echo $1
newstr=$(tr '[A-Z]' '[a-z]' <<<"$1")
if [[ $newstr != *.png ]]; then
echo "\033[31m 图片不是png格式 \033[0m"
exit
fi

if [ x"$2" = x ]; then
echo "\033[31m 请输入iconset目录(命名方式xxx.iconset, 务必以 .iconset 结尾) \033[0m"
exit
fi

if [[ $2 != *.iconset ]]; then
echo "\033[31m iconset目录命令不规范 \033[0m"
exit
fi
# 生成的图片名
name_array=("icon_16x16.png" "icon_16x16@2x.png" "icon_32x32.png" "icon_32x32@2x.png" "icon_128x128.png" "icon_128x128@2x.png" "icon_256x256.png" "icon_256x256@2x.png" "icon_512x512.png" "icon_512x512@2x.png")
#尺寸
size_array=("16" "32" "32" "64" "128" "256" "256" "512" "512" "1024")

# 创建 iconset 目录
if [ ! -d $2 ]; then
mkdir $2
fi

for ((i = 0; i < ${#name_array[@]}; ++i)); do
m_dir=$2/${name_array[i]}
sips -z ${size_array[i]} ${size_array[i]} $1 --out $m_dir
done
# 生成icns 命令
iconutil -c icns $2 -o ${2%*".iconset"}.icns
# 生成完之后删除 iconset 文件夹
rm -rf $2;

图标下载

当然,你也可以去下载现成的 macOS Big Sur - Replacements Icons

图标还原

如果想恢复成默认图标,只需要在对应的APP图标上“右键”>“显示简介”,然后选中左上角的图标,按delete键就好了

3 关于.DS_Store 文件

阻止 DS_Store 文件的自动生成

DS_Store 文件是由系统自动创建的,它的存在有时候会对某些场景下的用户体验产生一些负面的影响。

为了加快网络磁盘的浏览速度,苹果提供了针对通过SMB共享的网络磁盘上DS_Store文件的阻止生成方案:

  1. 在「访达」中打开「应用程序」 > 「实用工具」 > 「终端」。

  2. 输入以下命令:

1
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool TRUE
  1. 然后退出登录 macOS 账户并重新登录。

要重新启用,请输入以下命令:

1
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool FALSE

但是,以上命令只是针对网络磁盘,想要阻止本地磁盘中 DS_Store 文件的自动生成?

唯一的方式就是停止使用「访达」,不过我想大家应该不会考虑这么做。

如何删除 DS_Store 文件

首先,要声明的一点是,删除 DS_Store 文件完全是安全的操作,它不会损害电脑,也不会造成个人数据丢失。删除后,「访达」在打开文件夹是会以默认显示模式显示文件夹。在你进行某些「访达」操作后,系统又会在后台自动创建 DS_Store 文件。

如果你想删除 DS_Store 文件,可以通过「终端」App 进行删除。

  1. 在「访达」中打开「应用程序」> 「实用工具」 > 「终端」。
  2. 定位到你要删除 .DS_Store 文件的文件夹目录下。
  3. 在「终端」里输入cd命令,跟上你的目录文件夹路径,例如: cd /Users/username/pictures
  4. 回车。
  5. 输入命令 find . -name '.DS_Store' -type f -delete
  6. 再次回车。

到这里,当前文件夹目录下的所有 .DS_Store 文件都会消失。

让你的各种网络密码无法被人破解

让你的各种网络密码无法被人破解

互联网产品各种各样,我们也就拥有了各种各样的帐号密码。网银密码,网站密码等等,大家一般化为了好记,都设置同一个密码,或者很简单的密码。这样就造成自己的帐号被黑客窃取。密码要想不被黑客猜中,有几点非常重要的注意事项

1、不要靠字典中的单词:如果你的密码可以在单词书中找到,那就和没有一样。黑客们经常借助词典以及词汇的变体测试密码.如果你不属于这一类,他们通常就会放弃。

2、一个密码绝对不要使用两次:人们喜欢在不同的网站使用同一密码,这可让黑客有了可乘之机。如果你的LinkedIn账户遭泄露,可能没什么损失;但他们会利用该密码尝试你的电子邮箱、银行账户等一切存储资产及重要个人数据的地方。

3、设置密码短语。密码越长,破解的时间也越长。如果不想让黑客在24小时内能破解你的密码,密码长度应该超过14个字符。因为长密码难于记忆,可考虑用喜欢的电影台词、歌词或一首诗的首字母拼接在一起。

4、胡乱敲击键盘:对于敏感的账户,格罗斯曼先生建议随机乱敲键盘,并间或敲击Shift和Alt键,然后将结果复制到一个文本,存入一个有密码保护的U盘。

5、安全存储你的密码。不要将密码放在收件箱或桌面。如果恶意软件感染电脑,你就完蛋了。格罗斯曼先生将密码文件存入加密U盘,使用帐户时,他把这些密码复制粘贴过去。即便黑客利用键盘记录软件,同样无法捕捉到他的密码。科克先生则把密码提示保存一张纸上,把敏感的信息和互联网彻底隔离。

6、不要依赖密码管理器。密码保护软件可使用户将所有用户名和密码存储在同一区域。有些程序还能为你创建强大的密码,只要你输入主密码,就能帮你自动登录网站。如LastPass、SplashData和AgileBits等等。科克先生认为,即使加密后,密码仍然留在计算机里。如果电脑遭到盗窃,等于丢失所有密码。而且密码管理器不一定靠谱,今年初在阿姆斯特丹举行的安全会议上,黑客们就演示了破解手机密码管理器的技术。

7、安全问题最好答非所问。网站的验证问题经常问道“你最喜欢什么颜色?”“你在哪所中学就读?”,这些问题的答案局限性太大,很容易在互联网上找到。今年初,一名黑客利用米特?罗姆尼(Mitt Romney)最喜欢的宠物的名字破解其Hotmail和Dropbox帐户。比较安全的做法是密码提示和问题无关。如果安全问题问出生医院的名称,你的回答可以是最喜欢的歌词。

8、使用不同的浏览器。不同的网络活动要用不同的浏览器。选择一个浏览器做乱七八糟的事情,如浏览网上论坛、新闻网站、博客等不重要的事情。第二个浏览器用于登录网上银行或收发电子邮件。这样浏览器被攻击后,银行帐户就不一定会泄露。Accuvant Labs去年研究发现,在其所调查的火狐、谷歌Chrome及微软Internet Explorer浏览器中,Chrome最安全。

9、别乱分享你的信息。不要经常利用真实的E-mail地址注册网上帐户。很多“一次性”e-mail地址是最佳选择,如10minutemail.com提供的地址,用户注册、确认在线账户后,这些电子邮件地址会自我销毁。

10、输入任何密码之前一定要搞清楚你当前访问的地址是你想要访问的地址,特别是现在的应用总喜欢用内置的浏览器打开网址,像微信、各个邮箱客户端,打开的网站并不会显示url地址,这样很容易就会碰到李鬼而没有发现。博主最近邮件收到一封自称是纪委的调查邮件,附件是一张二维码,扫码后转到到网易邮箱登录界面,因为是微信打开的网址,所以没有显示地址,用浏览器打开后发现是李鬼,随便用一个账号密码登录之后显示密码错误,然后就转跳到李逵哪里去了。

地址访问截图

最后分享一下我的密码设置规则:

我的网络账户被分为3个等级:

1 普通账户,用在一些普通论坛上,比如某一天搜到一个需要的文件在一个论坛里,但是必须注册账户才能下载,这时候就可以用普通账户,可以选择一个统一的账户名和密码,我的用户名就是redtux,密码是好多年前在一个网站上看到的一句话的首字母缩写。用户名要选择一个不容易重复的,我的这个组合用了10多年了,很多时候在一个网站注册的时候发现用户名已经注册了,我就用我的固定账户密码登录就可以进去了。

2 知名一点的账户,QQ,微信,百度,网易之类,用普通账户的密码跟对应网站的名字组合,比如网易密码可以是 普通密码@WangYi,你只要记住一个固定的组合规则,登录的时候就自动能生成密码。

3 涉及财产安全的,银行类,支付宝类的,方法同2,但是生成规则更复杂一点,比如可以加入更多的特殊符号。

这样子就只要记住一个密码和2种规则,就能保证所有账户的密码都不一样,如果其中一个网站被暴库也能保证其他网站的账号安全。