创建Docker的远程浏览器

docker load -i chromium-chatgpt.tar

docker run -d \
–name=chromium \
–security-opt seccomp=unconfined \
-e PUID=1000 \
-e PGID=1000 \
-e CUSTOM_USER=zeno \
-e PASSWORD=password \
-e TZ=Asia/Shanghai \
-e LC_ALL=zh_CN.UTF-8 \
-e CHROME_CLI=https://www.chatgpt.com \
-p 3000:3000 \
-p 3001:3001 \
-v /docker/appdata/firefox:/config \
–shm-size=”1gb” \
–restart unless-stopped \
chromium-chatgpt

发表在 Linux | 创建Docker的远程浏览器已关闭评论

这里是使用WARP Client进行代理解锁Netflix等。 可以去cloudfalre官方页面有详细的安装流程和原理,不赘述。 个人认为官方socks这种代理方式更灵活且优雅。

这里写下我的配置过程

0.安装与注册服务

ubuntu

# Add cloudflare gpg key
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg


# Add this repo to your apt repositories
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list


# Install
sudo apt-get update && sudo apt-get install cloudflare-warp

ArchLinux

pacman -U cloudflare-warp-bin-2024.4.133-2-x86_64.pkg.tar.zst
systemctl start warp-svc

1.注册客户端

warp-cli registration new

2.设置WARP代理模式

warp-cli set-mode proxy
# new version
warp-cli mode proxy

3.连接WARP

warp-cli connect

此时WARP会使用socks5本机代理127.0.0.1:40000 4.打开warp always-on

warp-cli enable-always-on

6.测试socks代,理检查ip是否改变

export ALL_PROXY=socks5://127.0.0.1:40000
curl ifconfig.me

7.修改v2ray/xray outbounds和分流规则,这里给出我的配置可自由发挥。

inbounds要启动sniffing

      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
   "outbounds": [
    {
      "protocol": "freedom",
      "tag": "DIRECT"
    },
    {
      "tag":"socks_out",
      "protocol": "socks",
      "settings": {
          "servers": [
              {
                "address": "127.0.0.1",
                "port": 40000
              }
          ]
      }
    },
    {
      "protocol": "blackhole",
      "tag": "BLOCK"
    }
  ],
  "routing": {
    "rules": [
      {
        "type": "field",
        "outboundTag": "socks_out",
        "domain": ["geosite:netflix"]
      },
      {
        "ip": [
          "geoip:private"
        ],
        "outboundTag": "BLOCK",
        "type": "field"
      },
      {
        "domain": [
          "geosite:private"
        ],
        "outboundTag": "BLOCK",
        "type": "field"
      },
      {
        "protocol": [
          "bittorrent"
        ],
        "outboundTag": "BLOCK",
        "type": "field"
      }
    ]
  }

8.重新启动v2ray/xray

systemctl restart v2ray/xray
systemctl status v2ray/xray

xray可能需要下载geosite和geoip, google github上就能找到,下载后放在 /usr/local/bin

发表在 Linux | 已关闭评论

chisel:一款快速稳定的隧道工具

下载

https://github.com/jpillora/chisel

这是一款采用Go编写的工具,支持多平台的使用。

A fast TCP/UDP tunnel over HTTP

这款工具底层采用了HTTP进行传输,将TCP/UDP链接封装在HTTP隧道中,并且还使用了SSH对通信数据进行加密。

这里先上一张我梳理过的脑图

程序只有一个二进制文件,客户端和服务端都包含在其中,通过给定参数运行客户端或服务端。

端口转发

首先我在服务器执行启动一个http服务器,并且该服务器只对本地端口开放。

python3 -m http.server –bind 127.0.0.1 8000

那么为了在其他电脑上能访问到这个http服务,我们就需要做端口转发。

正向连接
在服务器(192.168.61.128)上执行

./chisel server -p 12345

在客户端(192.168.61.129)上执行

chisel.exe client 192.168.61.128:12345 11111:127.0.0.1:8000

通过与192.168.61.128:12345建立隧道,然后本地使用1111端口,映射到目标的8000端口

然后在客户端计算机上直接打开网页即可访问到服务器上的http服务

反向连接

在客户端(192.168.61.129)上执行

chisel.exe server -p 12345 --reverse

在服务器(192.168.61.128)上执行

./chisel client 192.168.61.129:12345 R:11111:127.0.0.1:8000

通过与192.168.61.129:12345建立隧道,然后反向把目标的11111端口映射到本地的8000端口

与上面的例子类似, 可以在客户端计算机上打开对应的网页

发表在 C/C++ | chisel:一款快速稳定的隧道工具已关闭评论

Telegram双向机器人的搭建

一、通过@BotFather申请一个机器人Token

二、建立一个群组,设置为私有模式

三、打开群组的话题功能

四、将自己的机器人,拉入群组。提升权限为管理员

五、管理权限切记包含消息管理话题管理

六、部署

1.获取代码/构建python venv

pacman -S gcc python-pip python-virtualenvwrapper
/usr/bin/virtualenvwrapper.sh chatbot_env
/usr/bin/python -m venv /srv/chatbot_env
/srv/chatbot_env/bin/pip install --upgrade pip
/srv/chatbot_env/bin/pip install setuptools

git clone https://github.com/MiHaKun/Telegram-interactive-bot.git
mv Telegram-interactive-bot chatbot
cd chatbot
/srv/chatbot_env/bin/pip install -r requirements.txt

2.修改env

打开.env_example,将自己机器人的Token、账号的API_ID/HASH、管理群组ID和管理员ID补全。 另存.env_example.env

/srv/chatbot_env/bin/python -m interactive-bot

3.编写启动脚本

nano -w /usr/lib/systemd/system/chatbot.service

[Unit]
Description=Telegram Interactive Bot Service
Documentation=https://github.com/MiHaKun/Telegram-interactive-bot
After=network.target nss-lookup.target

[Service]
ExecStart=/srv/chatbot_env/bin/python -m interactive-bot
Restart=on-failure
WorkingDirectory=/srv/chatbot

[Install]
WantedBy=multi-user.target

发表在 Python | Telegram双向机器人的搭建已关闭评论

Metronic 使用Gulp/webpack打包静态资源

1.安装node.js && npm

brew install node

2.安装yarn

npm install --global yarn

3.安装gulp

npm install --global gulp-cli

如果有的话,可以删除

npm rm --global gulp

4.安装Metronic的依赖包

使用下面的指令,编译所有的静态资源(sass, js, media) 到 assets/ 目录: 可以指定编译的目录. 比如. --dist

cd tools/
gulp --dist

Metronic 默认采用的gulp编译的,如果要使用webpack,需要删除 tools/package.json 中的 "type": "module"

cd tools/
npm run build

5.复制生成的静态资源

                    <execution>
                        <id>position-react-static-build</id>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <phase>prepare-package</phase>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/static/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${basedir}/frontend/dist</directory>
                                    <filtering>false</filtering>
                                    <includes>
                                        <include>assets/**</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
发表在 Javascript | Metronic 使用Gulp/webpack打包静态资源已关闭评论

dispatch_async 子线程,主线程的简单用法

子线程的使用方法:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     //子线程的处理逻辑  
});


DISPATCH_QUEUE_PRIORITY_DEFAULT 代表队列的优先级,包含以下参数
 DISPATCH_QUEUE_PRIORITY_HIGH, 
 DISPATCH_QUEUE_PRIORITY_LOW,   
 DISPATCH_QUEUE_PRIORITY_BACKGROUND
 0 是一个保留值,暂时没有任何效果,默认传个0就可以了

主线程的使用方法:

dispatch_async(dispatch_get_main_queue(), ^{
     //主线程的处理逻辑
});

如果子线程里面还需要更新一些UI之类的操作,这个时候就需要在主线程里面去完成,就是说子线程里面可以嵌套主线程,具体的使用方法如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     //子线程的处理逻辑
               
    dispatch_async(dispatch_get_main_queue(), ^{
        //主线程更新UI之类的操作
    });
               
});
发表在 Objective-C | dispatch_async 子线程,主线程的简单用法已关闭评论

Using SCLAlert as HUD

In your class.h file interface:

SCLAlertView *hud;
NSString *hudTitle;
NSString *hudText;

In your class.m file provide these methods:

 -(void)startHud {

    [self.view endEditing:YES]; //make sure keyboard is down

    hud = [[SCLAlertView alloc] init];
    [hud setShowAnimationType:SlideInToCenter];
    hud.backgroundType = Blur;
    hud.customViewColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.7f]; //set custom color
    [hud setHideAnimationType:SlideOutFromCenter];
    [hud showWaiting:self title:hudTitle
    subTitle:hudText
    closeButtonTitle:nil duration:0];
}

-(void)stopHud {
    [hud setHideAnimationType:SlideOutToCenter];
    hudText = @"";
    hudText = @"";
    [hud hideView];
}

Now wherever you want to invoke the spinner simply:

                    hudTitle = NSLocalizedString(@"Processing Authorization", nil);
                    hudText = NSLocalizedString(@"Communicating with host...", nil);
                    [self startHud];

Wherever you want to hide the spinner:

                   [self stopHud];

Taking this a step further combining with SCAlerts:

                [alert addButton:NSLocalizedString(@"Authorization", nil) actionBlock:^{
                    hudTitle = NSLocalizedString(@"Processing Authorization", nil);
                    hudText = NSLocalizedString(@"Communicating with host...", nil);
                    [self saveObject];   //invoke some method
                    return;
                }];

                [alert addButton:NSLocalizedString(@"Update Application", nil) actionBlock:^{
                    hudTitle = NSLocalizedString(@"Update Application", nil);
                    hudText = NSLocalizedString(@"Communicating with host...", nil);
                    [self updateObject];   //invoke some other method
                    return;
                }];

in your method (saveObject);

-(void)saveObject {
    [self startHud];
    // do something
    [self stopHud];
}
发表在 Objective-C | Using SCLAlert as HUD已关闭评论

在Objective-C中的类与对象

一·类与对象

定义类:
面向对象的程序设计过程中有两个重要概念:类与对象,也是称为实例。其中类是某一批对象的抽象,可以把类理解成某种概念;对象是一个存在的实体。
定义类的步骤:

接口部分是对成员变量进行定义,而实现部分是对方法的精细化。
方法声明的语法:

类的实现语法

代码展示:
对象的产生与使用

  • 定义变量
  • 创建对象
  • 接口与实现部分
#import <Foundation/Foundation.h>

//接口部分
@interface FKPerson : NSObject {    //@interface是开始的标志
    //下面定义了两个成员变量
    NSString* _name;
    int _age;
}
//下面定义了一个setName: andAge: 方法
- (void) setName :(NSString *) name andAge : (int) age;
//下面定义了一个say: 方法, 并不提供实现
- (void) say: (NSString *) content;
//下面定义了一个不带形参的info方法
- (NSString*) info;
//定义一个类方法
+ (void) foo;
@end        //@end是结束的标志


//实现部分
@implementation FKPerson {
    //定义一个只能在实现部分使用的成员变量 (被隐藏的成员变量)
    int _testAttr;
}
//定义一个只能在实现部分使用的方法
- (void) test {
    NSLog(@"--只能实现部分定义的test方法--");
}
//下面定义了一个setName: andAge: 方法
- (void) setName :(NSString *) n andAge: (int) a {
    _name = n;
    _age = a;
}
//下面定义了一个say: 方法, 并不提供实现
//"say:"有冒号的表示有形参的方法
- (void) say: (NSString *) content {
    NSLog(@"%@", content);
}
//下面定义了一个不带形参的info方法
- (NSString*) info {
    [self test];
    return [NSString stringWithFormat:@"我是羽毛球选手,名字为:%@,年龄为%d。", _name, _age];
}
+ (void) foo  {
    NSLog(@"FKPerson类的类方法,通过类名调用");
}
@end

//对象的产生与实现
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKPerson* person = [[FKPerson alloc] init];
        //init初始化  alloc分配内存
        [person say: @"hello i love iOS"];
        [person setName:@"何斐" andAge: 19];
        NSString* info = [person info];
        NSLog(@"person -info 的信息为:%@",info);
        [FKPerson foo];
    }
    return 0;
}

self关键字
OC提供了一个self关键词,关键词总是指向调用该方法的对象。
self关键词最大的作用是让类中的一个方法访问该类的另一方法或成员变量。
代码展示:
重要的批注都在代码中。

#import <Foundation/Foundation.h>
//首先是声明部分
@interface FKDog : NSObject
- (void) jump;
- (void) run;
@end
//再是实现部分
@implementation FKDog
- (void) jump {
    NSLog (@"正在执行jump方法");
}
- (void) run {
    //无self的时候,要新创建一个FKDog的对象
    //FKDog* d = [[FKDog alloc] init];
    //[d jump];
    //self不能出现在类方法中;当出现在调用的方法中,它代表的对象不确定,只有被调用的时候才可以确定。
    [self jump];
    NSLog(@"正在执行run方法");
}
@end
//主函数部分
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKDog* dog = [[FKDog alloc] init];
        [dog jump];
        [dog run];
    }
    return 0;
}

d关键词
id可以表示所有对象的类型,任意类的对象都可以复制给id类型变量。
当通过id类型的变量来调用方法时,oc就将会执行动态绑定,oc将会跟踪对象所属的类,并在运行时判断该对象所属的类,而不是在编译时确定要调用的方法。

//例如下面的示例代码:
#import <Foundation/Foundation.h>
@interface FKPerson : NSObject {    //@interface是开始的标志
    //下面定义了两个成员变量
    NSString* _name;
    int _age;
}
- (void) say: (NSString *) content;
@end
@implementation FKPerson
- (void) say : (NSString *) content {
    NSLog(@"%@", content);
}
@end
int main (int argc , char * argv[] ) {
    @autoreleasepool {
   		//定义id类型的变量,并将FKPerson对像赋值给该变量
        id p = [[FKPerson alloc] init];
        //使用p变量来调节say:方法
        //程序将在运行时执行动态绑定。
        [p say:@"疯狂iOS讲义"];
    }
    return 0;
}

形参个数可变的方法
在定义方法时,在最后一个形参名后增加逗号和三点(,…),则表明该形参可以接受多个参数值。下面是定义形参可变的方法。
为了在程序中获取个数可变的参数,需要使用如下关键字

#import <Foundation/Foundation.h>
@interface VarArgs : NSObject
//定义一个形参可变的方法
- (void) test: (NSString*) name, ...;
@end
@implementation VarArgs
- (void) test: (NSString* ) name, ... {
    //使用va_list定义一个argList指针变量,该指针变量指向可变参数列表
    va_list argList;
    //如果第一个name参数存在,才需要处理后面的参数
    if (name) {
        //由于name参数并不在可变参数列表中,因此先处理name参数
        NSLog(@"%@", name);
        //让argList指向第一个可变参数列表的第一个参数,开始提取可变参数的列表
        va_start(argList, name);
        NSString* arg = va_arg(argList, id);
        //va_arg用于提取argList指针当前指向的参数,并将参数指针移动到只想下一个参数
        //arg变量用于保存当前获取的参数,如果该参数不为nil,进入循环体
        while (arg) {
            //打印每一个参数
            NSLog(@"%@", arg);
            //再次提取下一个参数,并将指针移动到指针指向下一个参数
            arg = va_arg(argList, id);
        }
        //释放argList指针,结束提取
        va_end(argList);
    }
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        VarArgs* va = [[VarArgs alloc] init];
        [va test:@"疯狂iOS讲义", "疯狂Android讲义", "疯狂Ajax讲义", nil];
    }
    return 0;
}

模拟类变量
OC并不支持类似于Java的类变量,为了模拟类变量,可以在类实现部分定义static修饰的全局变量,并提供一个类方法来暴露该全局变量。
FKUser的接口部分声明两个类方法分别用于修改或获取类变量,示例代码如下:

模拟类的变量
#import <Foundation/Foundation.h>
@interface FKUser : NSObject
+ (NSString* ) nation;
+ (void) setNation: (NSString* ) newNation;
@end
static NSString* nation = nil;
@implementation FKUser
+ (NSString* ) nation {
    //返回nation全局变量
    return nation;
}
+ (void) setNation:(NSString *)newNation {
    //对nation全局变量赋值
    if (![nation isEqualToString: newNation]) {
        nation = newNation;
    }
}
@end
int main (int argc , char * argv[] ) {
    @autoreleasepool {
        //为FKUser的类赋值
        [FKUser setNation: @"陕西"];
        //访问FKUser的类变量
        NSLog(@"FKUser的nation类变量为: %@",[FKUser nation]);
    }
    return 0;
}

单例模式
如果一个类始终只能创建一个实例则这个类被称为单例类。
单例类通过static全局变量来实现,每次程序需要获取该实例时,程序首先判断该static全局变量是否为nil,则初始化一个实例并赋值给全局变量。

//代码如下
#import <Foundation/Foundation.h>
@interface  FKSinglenton: NSObject
+ (id) instance;
@end
static id instance = nil;
@implementation FKSinglenton
+ (id) instance {
    //如果instance为nil
    if (!instance) {
        //创建一个Singletion实例,并将该实例赋值给instance全局变量
        instance = [[super alloc] init];
    }
    return instance;
}
@end
int main (int argc , char * argv[] ) {
    @autoreleasepool {
        //判断两次获取的实例是否相等,程序返回1,(代表真)。
        NSLog(@"%d" ,[FKSinglenton instance] == [FKSinglenton instance]);
    }
    return 0;
}
发表在 Objective-C | 在Objective-C中的类与对象已关闭评论

在Objective-C中的方法

在Objective-C中,方法可以分为两种类型:实例方法和类方法

1. 实例方法(Instance Methods):
实例方法是与类的实例相关联的方法。它们依赖于实例的状态并对其进行操作。如果想要调用对象方法就必须要先创建对象通过对象名来调用,实例方法使用加号(-)符号来声明和实现

@interface MyClass : NSObject
- (void)doSomething;
@end
 
@implementation MyClass
- (void)doSomething {
    // 实例方法的实现
    // ...
}
@end
 
// 调用实例方法
MyClass *myObject = [[MyClass alloc] init];
[myObject doSomething]; // 使用方括号调用
myObject.doSomething; // 使用点语法调用

2. 类方法(Class Methods):
类方法是与类本身相关联的方法,而不是类的实例。它们不依赖于特定的实例并可以直接通过类名来调用。类方法使用加号(+)符号来声明和实现

@interface MyClass : NSObject
+ (void)doSomething;
@end
 
@implementation MyClass
+ (void)doSomething {
    // 类方法的实现
    // ...
}
@end
 
// 调用类方法
[MyClass doSomething]; // 使用方括号调用
MyClass.doSomething; // 使用点语法调用

在方法的定义中,实例方法以减号(-)开头,类方法以加号(+)开头。这是Objective-C的命名约定,并有助于区分不同类型的方法。

在类方法中不能直接访问属性.
1),属性是在对象创建的时候.跟随着对象一起创建在对象之中.
2),类第1次被访问的时候,会做类加载,是把类的代码存储在代码段
因为属性只有在对象创建的时候才会创建在对象之中,
而类方法在执行的时候,有可能还没有对象。没有对象,没法访问属性,
虽然不能直接访问属性,但是我们可以在类方法中创建1个对象访问这个对象的属性,
在类方法中也不能通过self直接调用当前类的其他的对象f方法
因为对象方法只能通过对象来调用而这个时候没有对象,

发表在 Objective-C | 在Objective-C中的方法已关闭评论

mac环境下 使用ffmpeg调用摄像头推流到rstp-simple-server

1. 先安装ffmpeg,然后启动

先使用ffmpeg列出可用设备

#列出可用设备
ffmpeg -list_devices true -f dshow -i dummy 

启动命令如下:(可以将设备名称替换成自己的)

​​​​​​​ffmpeg -f avfoundation -framerate 30 -video_size 640x480 -i "0:0" -vcodec libx264 -preset veryfast -f rtsp rtsp://localhost:8554/live/room1

ffmpeg -re -i r1.mp4 -c copy -f flv rtmp://192.168.110.248:1935/live/now

发表在 Mac | mac环境下 使用ffmpeg调用摄像头推流到rstp-simple-server已关闭评论