普通视图

发现新文章,点击刷新页面。
昨天以前旁逸斜出

公网ip访问emby添加自定义SSL证书

作者 who
2025年11月30日 20:53

当我们用ip:端口号的形式直接访问emby的时候,http明文传输不安全(当然有人用域名解析,申请域名的ssl证书,这也是很好的方案),下面演示如何添加emby自定义SSL证书

生成PKCS#12 文件

在linux下(windows自行百度在线生成网站)

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes -subj "/CN=MyEmby"
  • openssl req -x509: 告诉系统,“我要申请一张证书,而且我自己签字生效”(这就是自签名)。
  • newkey rsa:4096: “给我造一把新的私钥,加密强度要最高级别的 4096 位”
  • keyout key.pem: “把私钥保存为 key.pem”。
  • out cert.pem: “把公钥(身份证)保存为 cert.pem”。
  • days 3650: “这张身份证的有效期是 3650 天(大约 10 年)”
  • nodes: “私钥文件不要加密”。这意味着 Emby 读取它时不需要你每次手动输入密码,方便自动启动。
  • subj "/CN=MyEmby": “证书的主人名字叫 MyEmby”。这避免了系统问你一堆问题(比如你叫什么、在哪个国家、哪个城市等),直接填好

执行完上面的命令后就会生成cert.pem和key.pem

接下来生成emby需要的格式证书

openssl pkcs12 -export -out emby.p12 -inkey key.pem -in cert.pem -passout pass:123dfas
  • openssl pkcs12 -export: “我要把刚才那两个文件打包导出”。
  • in cert.pem 和 -inkey key.pem: “要把刚才生成的身份证和钥匙放进去”。
  • out emby.p12: “打包好的文件名字叫 emby.p12”。
  • passout pass:123456: “给这个包裹上把锁,密码是 123dfas”,密码自行修改

执行完会生成emby.p12

emby服务器配置

emby服务器-设置-网络自定义SSL证书路径选择刚才生成的emby.p12(脚本执行在哪个路径,就会生成在哪个路径),证书密码填上一步时的密码,点击页面下方的保存,重启服务器
emby默认https访问端口号8920,可以在浏览器测试https://xxx.xxx.xxx.xxx:8920,因为这个是自定义证书,浏览器会报警,但是是加密的,点击继续访问即可
如果是客户端,连接时会弹出提示,接受证书即可

印象中的音乐

作者 who
2023年10月19日 21:00

音乐对于影视剧的重要程度毋庸置疑,即便像我这种没什么音乐细胞的人,也记得一些场景。

娄烨导演的电影《风中有朵雨做的云》,讲述了社会发展过程中,因钱、因权、因情、因恨发生的一桩故事。故事结局,影片中的主人公各自落了个悲催的结果。当片尾歌曲《一场游戏一场梦》兀自响起,观众突然清醒过来:可不就是一场游戏一场嘛,是可悲呢,还是可惜呢,就留给您听着歌自己体会了。 http://music.163.com/song?id=158924

台湾电影《大佛普拉斯》非常辛辣和残忍地对比展现了社会贫富的巨大差距。当片尾曲《有无》响起,虽然歌词听不懂,但似乎有一种大佛看透尘世确仍保着对众生地关怀。
http://music.163.com/song?id=484056998

贾樟柯的电影一直有非常鲜明的时代声音,《三峡好人》当中的小男孩站在船头,扯着嗓子唱《老鼠爱大米》,当时不懂导演想表达什么,确也记忆深刻。

上高中时,每天都睡眠不足。下午吃完饭去上晚自习那会儿一天中经常犯困的时间之一,去了会先进行听力练习,广播里每次都会放《Trouble Is A Friend》,每当明快的旋律想起,就会觉得困意消散了很多。直到现在听起这个,总是会想起当初的时光。

突然发现这些音乐总是跟具体的事物关联在了一起,好像单纯听音乐这件事也变得不那么纯粹了,哈哈,大概是缺乏音乐细胞并且想象力不足吧。

C#AutoResetEvent和ManualResetEvent介绍

作者 who
2022年11月28日 19:19

AutoResetEvent和ManualResetEvent是c#用来线程同步的。

AutoResetEvent

参考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.autoresetevent?view=net-7.0

Set():将事件设置为已发送信号状态,对于AutoResetEvent来说允许一个正在等待的线程继续执行。如果没有线程在等待,将保持无限期有信号状态。

WaitOne():处于无信号状态时,阻塞当前线程直到接收到了信号量

如果线程在处于信号状态时AutoResetEvent调用WaitOne,则线程不会阻塞。AutoResetEvent立即释放线程并返回到无信号状态。也就是说如果没有线程在WaitOne,先执行了Set,会导致后调用的第一次WaitOne失效不阻塞,第二次调用WaitOne阻塞会生效

using System;
using System.Threading;

namespace AutoResetEvent_Examples
{
    class MyMainClass
    {
      const int numIterations = 100;
      static AutoResetEvent myResetEvent = new AutoResetEvent(false);
      static int number;
      
      static void Main()
        {
         //定义线程并启动,MyReadThreadProc方法接收到信号量后读取当前线程的名字和number并打印
         Thread myReaderThread = new Thread(new ThreadStart(MyReadThreadProc));
         myReaderThread.Name = "ReaderThread";
         myReaderThread.Start();
         for(int i = 1; i <= numIterations; i++)
         {
            Console.WriteLine("Writer thread writing value: {0}", i);
            number = i;
            
            //Signal that a value has been written.
            //调用Set()后MyReadThreadProc()从WaitOne()继续执行
            myResetEvent.Set();
            
            //Give the Reader thread an opportunity to act.
            Thread.Sleep(1);
         }

         //Terminate the reader thread.
         myReaderThread.Abort();
      }

      static void MyReadThreadProc()
      {
         while(true)
         {
            //The value will not be read until the writer has written
            // at least once since the last read.
            myResetEvent.WaitOne();
            Console.WriteLine("{0} reading value: {1}", Thread.CurrentThread.Name, number);
         }
      }
    }
}

官网拷贝的代码,只有当Main()中的for循环调用myResetEvent.Set(),MyReadThreadProc()才会收到信号来读取当前线程的名字,否则就会一直停在myResetEvent.WaitOne()而不会继续向后执行。

ManualResetEvent

参考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.manualresetevent?view=net-7.0

Set():将事件设置为已发送信号状态,对于ManualResetEvent来说允许所有正在等待的线程继续执行

Reset():设置事件无信号,使能够继续阻塞线程

using System;
using System.Threading;

public class Example
{
    // mre is used to block and release threads manually. It is
    // created in the unsignaled state.
    private static ManualResetEvent mre = new ManualResetEvent(false);

    static void Main()
    {
        Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");
        //定义三个线程
        for(int i = 0; i <= 2; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }

        Thread.Sleep(500);
        Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
                          "\nto release all the threads.\n");
        Console.ReadLine();
        //给信号使ThreadProc()中的WaitOne()之后的代码执行
        mre.Set();

        Thread.Sleep(500);
        Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
                          "\ndo not block. Press Enter to show this.\n");
        Console.ReadLine();

        for(int i = 3; i <= 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }
        //ManualResetEvent在调用Set()之后,WaitOne()并不会阻塞线程,要想阻塞线程,需要调用Reset()使没有信号,才能够继续阻塞线程
        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
                          "\nwhen they call WaitOne().\n");
        Console.ReadLine();
        //调用Reset()后继续阻塞线程
        mre.Reset();

        // Start a thread that waits on the ManualResetEvent.
        Thread t5 = new Thread(ThreadProc);
        t5.Name = "Thread_5";
        t5.Start();

        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
        Console.ReadLine();

        mre.Set();

        // If you run this example in Visual Studio, uncomment the following line:
        Console.ReadLine();
    }

    private static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine(name + " starts and calls mre.WaitOne()");

        mre.WaitOne();

        Console.WriteLine(name + " ends.");
    }
}
/*

Start 3 named threads that block on a ManualResetEvent:

Thread_0 starts and calls mre.WaitOne()
Thread_1 starts and calls mre.WaitOne()
Thread_2 starts and calls mre.WaitOne()

When all three threads have started, press Enter to call Set()
to release all the threads.


Thread_1 ends.
Thread_0 ends.
Thread_2 ends.

When a ManualResetEvent is signaled, threads that call WaitOne()
do not block. Press Enter to show this.


Thread_3 starts and calls mre.WaitOne()
Thread_3 ends.
Thread_4 starts and calls mre.WaitOne()
Thread_4 ends.

Press Enter to call Reset(), so that threads once again block
when they call WaitOne().


Thread_5 starts and calls mre.WaitOne()

Press Enter to call Set() and conclude the demo.

Thread_5 ends.

*/

简单总结一下二者区别:

1.AutoResetEvent调用Set只给一个正在WaitOne的线程信号使之继续执行,ManualResetEvent调用Set会给所有正在WaitOne的线程信号使之继续执行

2.在调用Set后ManualResetEvent将保持有信号状态,WaitOne将失效,不再进行线程阻塞,需要重新阻塞的话要调用Reset,但AutoResetEvent(在已经有线程WaitOne的情况下)会自动返回到无信号状态。

Android12、Android13、Android14的Root教程

作者 who
2022年4月1日 20:08

以前写过一篇刷机教程:https://www.mihu.live/archives/23/
但是后来随着Android12和新的magisk推出,root的方式发生了一些变化,重新写一篇单独root的教程
写在最前面:备份!备份!备份!
对于安卓12而言,建议使用修补boot的方式安装magisk,步骤依次是:
1.解锁
2.下载完整包
3.提取boot.img文件
4.安装magisk Alpha 版本
5.在magisk中 选择并修补一个文件
6.fastboot刷入修补boot生成的magisk_patched-xxxxx.img文件

解锁

小米解BL锁官网:http://www.miui.com/unlock/index.html
小米解锁帮助:http://www.mi.com/service/support/BL-loc
最新版的小米官方解锁工具要是遇到问题,建议下载个老版本解锁即可。
解锁后打开开发者模式,开启usb调试
如果是其它品牌手机,自行寻找方法
解锁会清除手机数据,提前备份。

下载完整包

建议在通过修补boot的方式安装magisk前先安装一次完整包(如果手机出厂就是Android12,也可以跳过这一步,建议不要跳过,下载最新完整包不会清除数据)
不管是否安装完整包,下载都是要的
以小米为例:
安装完整包
设置--我的设备--MIUI版本--右上角--下载最新完整包
下载完整包
但是上面的办法下载完成后会自动解密,手机就无法保存最新的完整包,所以对于只下载而言,有两种办法:
1.直接去小米社区对应手机板块下载对应的卡刷包(推荐使用)
2.设置--我的设备--MIUI版本--右上角--下载最新完整包,开始下载后打开系统app下载管理中手动暂停--设置中取消下载最新完整包,但是app下载管理中任务还在,继续下载就可以保存完整包

提取init_boot.img文件

这一步需要根据手机和系统版本而定
在手机完整系统包中找到init_boot.img(android 12及以前的版本是boot.img)

如果没有,则需要其他途径自己提取,下面是一个android 12的参考示例
需要从与当前系统版本一致的完整版安装包中提取东西,将完整版安装包拷到电脑上,安装包里面有一个payload.bin,直接拖出来或者解压后拿出来。
安装payload,地址:https://github.com/ssut/payload-dumper-go/releases,解压之后,拖拽payload.bin到payload-dumper-go.exe打开,就会在目录中多出一个文件夹,里面有一个boot.img,后面需要用。

安装magisk

在这里我们要下载 非官方版本 ,Alpha和Kitsune版本与官方版本的不同在于:官方版本无法隐藏Root,这样会导致银行或者其他检测设备是否Root的App在安装官方版本的Magisk之后无法使用,所以需要选择Alpha或Kitsune版本

官方版本:https://github.com/topjohnwu/Magisk/releases

Alpha 版本

下载地址:
1.https://install.appcenter.ms/users/vvb2060/apps/magisk/distribution_groups/public
2.https://t.me/s/magiskalpha
John Wu是magisk的主要开发者之一,但是Alpha版本他不再开发了,所以后来的Alpha版本是另外一个开发者(https://twitter.com/vvb2060) 在开发(包名为io.github.vvb2060.magisk),他没有开源代码。参考:https://twitter.com/topjohnwu/status/1492885858634006528

Kitsune Magisk(以前叫Magisk Delta):https://github.com/HuskyDG/magisk-files/releases

在magisk中 选择并修补一个文件

在手机上安装之后打开,在Magisk那一栏点击安装,选择并修补一个文件,选择init_boot.img,开始,完成后会在Download文件夹生成一个类似于magisk_patched-24305_Yzkiz.img的文件,magisk_patched-[随机字符串].img,将这个文件拷贝到电脑上

fastboot刷入修补init_boot生成的magisk_patched-xxxxx.img文件

手机进入fastboot模式(小米是电源键+音量下键,屏幕上会出现fastboot字样),插上电脑(手机要开启usb调试),在电脑上进入adb,
键入命令:

adb devices #检查是否正常启用usb调试模式,如果没有输出下面的设备列表,则需要检查自己电脑的驱动或手机设置
List of devices attached
xxxxxxxxxxxxx  device

fastboot flash init_boot magisk_patched-24305_Yzkiz.img(注意路径和文件名)
如果是android12及以前
fastboot flash magisk_patched-24305_Yzkiz.img(注意路径和文件名)

重启手机(fastboot rteboot也可以重启)

关于adb的使用的简单说明:
下载地址:https://developer.android.google.cn/studio/releases/platform-tools
下载完解压

方法一:
比如我的SDK工具包路径: E:\Program Files(x86)\platform-tools
cmd(win+r输入cmd回车)中输入:
E:
cd Program Files(x86)\platform-tools
进到SDK文件夹后执行:
fastboot flash boot magisk_patched-24305_Yzkiz.img
fastboot reboot
************************
方法二:
进入到platform-tools文件夹,在路径栏中输入cmd,与上面的效果一致

重启进入magisk可以看到当前的版本,root成功
完结!

刷完面具之后的ota升级参考:

1.升级之前在magisk中点击 卸载Magisk还原原厂映像
2.正常进行ota升级,到100%后不要立即重启手机,在magisk中点击 安装安装到未使用的槽位(OTA后) ,安装后重启手机
参考:
https://magiskcn.com/
https://sspai.com/post/53075

sqlsever代理启动失败

作者 who
2021年10月4日 19:04

sqlserver代理启动失败
日志提示:

2021-08-31 16:23:22 - ? [100] Microsoft SQLServerAgent 版本 11.0.3000.0 (内部版本号 X64 unicode 零售): 进程 ID 3244
2021-08-31 16:23:22 - ? [495] SQL Server 代理启动服务帐户是 NT SERVICE\SQLSERVERAGENT。
2021-08-31 16:23:22 - ! [150] SQL Server 不接受连接(错误: 0)。请等待 SQL Server 允许连接。尝试的操作为: 启动时验证连接。
2021-08-31 16:23:22 - ! [000] 无法连接到服务器“(local)”;SQLServerAgent 无法启动
2021-08-31 16:23:22 - ! [298] SQLServer 错误:  27,注册表信息已损坏或丢失。请确保已正确安装和注册提供程序。 [SQLSTATE 08001] 
2021-08-31 16:23:22 - ! [298] SQLServer 错误:  27,客户端无法建立连接 [SQLSTATE 08001] 
2021-08-31 16:23:22 - ! [165] ODBC 错误: 0,与 SQL Server 建立连接时发生了与网络相关的或特定于实例的错误。找不到或无法访问服务器。请检查实例名称是否正确以及 SQL Server 是否配置为允许远程连接。有关详细信息,请参阅 SQL Server 联机丛书。 [SQLSTATE 08001] 
2021-08-31 16:23:22 - ! [382] 无法登录到服务器“(local)”(DisableAgentXPs)
2021-08-31 16:23:22 - ? [098] SQLServerAgent 已终止(一般)

解决方案:
打开控制面板:找到2012 Native Client修复即可
注:Express Edition是不支持sqlserver代理功能的(select @@VERSION可以查看版本)

Sqlserver中0和空字符串相等的问题

作者 who
2021年8月17日 20:21

今天在SQL server中写存储过程时遇到一种0和空字符串相等的问题。
场景:表A有value1(varchar)和value2(int)两个字段,现在插入一条新的数据(v1,v2),如果v1已存在,则给value2加上v2,若v1不存在则插入新的(v1,v2)
(这个逻辑用merge into会更好些)
开始我是这么写的

declare @flag=int
select @flag=value2 from A where A.value1=v1
if(@flag='')
  insert into ...
else 
  update A...

但是这样是有问题的,当查询不到这条数据时,确实会插入,但是当value2=0的时候,这么写它依然会执行insert,也就是0='',可以通过下面的存储过程验证一下:

CREATE PROCEDURE TEST
AS 
BEGIN 
    declare @a int
    declare @b varchar
    set @a=0
    set @b=0
    if(@a='')
        print('int a')
    if(@b='')
        print('varchar b')
END
GO

然后执行会发现输出为 int a ,原因在于varchar和int是存在隐式转换的,导致转换之后0和空字符串变成了相等的。

参考:https://www.cnblogs.com/liubaolongcool/archive/2011/08/24/2152552.html

xml代码注释生成.chm文档

作者 yan
2021年7月14日 21:35

在Visual Studio中,在类和方法前面输入///会自动生成xml格式注释,只需要往节点里写对应的描述,关于更多的写法,参考
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/xmldoc/recommended-tags-for-documentation-comments

生成xml注释文档

在Visual Studio中,点击 项目 —— 项目的属性 —— 生成 ,勾选 输出 中的 XML文档文件 ,重新编译,这样就会在对应的路径生成xml注释文档。
VS生成xml文档
生成的xml文档

安装Sandcastle Help File Builder和HTML HELP

Sandcastle Help File Builder下载地址:https://github.com/EWSoftware/SHFB
HTML HELP下载地址: http://web.archive.org/web/20160201063255/http://download.microsoft.com/download/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe
(来自https://docs.microsoft.com/en-us/answers/questions/265752/htmlhelp-workshop-download-for-chm-compiler-instal.html
下载Sandcastle Help File Builder时需要注意支持的vs版本,Help File Builder and Tools v2019.11.17.0是最后一个支持vs2015的版本
v2019.11.17.0是最后支持VS2015的版本

安装Sandcastle Help File Builder

弹出HTML HELP 1 Compiler是选择是,之后再安装HTML HELP1
跳过html help安装
接下来install shfb——install package,剩下的高兴装就装。

安装HTML HELP

网盘里这个就是上面的链接下载下来的
链接:https://pan.baidu.com/s/1JPMMUqf4NE5icChcoLoN5w
提取码:gyl7
安装完会提示已经有一个更新版本的,忽略即可。
安装html help

生成.chm文档

方法一

VS新建一个 Documentation 项目,右键点击 Documentation Sources ,将刚才bin目录下的.xml和.exe文件添加进来,然后双击 Project Properties ,选择语言,Framework版本。
ContentLayout.content会在chm文件中生成Welcome和VersionHistory,如果不想要可以删除。
Documentation属性设置
在Visibility中可以选择生成的文档中包括的方法,这个会解决生成的.chm文档只有public类和方法或者类和方法不全的问题。
在Path中选择HTML HELP路径,可以解决Could not find the path to the HTML Help 1 compiler. Is the HTML Help Workshop installed?的问题(安装HTML HELP时默认路径应该不会有这个问题),还可以设置另外的输出路径。
设置html help路径
其他的设置按实际情况。
最后右键项目名——生成,就会在help文件夹生成.chm文件

方法二

打开Sandcastle Help File Builder安装目录下的SandcastleBuilderGUI.exe,新建一个项目,其余的配置和方法一一致,最后点击cpu架构右边的生成按钮,就会在对应的目录里生成.chm文档。
SHFB添加文件及配置

参考:https://www.pianshen.com/article/91331392251/

写于离开大学一年的日子

作者 yan
2021年7月11日 19:05

  去年的7月第二个星期天,也就是2020年7月12号,我和最后一个舍友告别,拉着行李箱,离开了我的大学。
  行李箱哐镗哐镗地响着,走在东门外的人行道上,望着信科院的大楼,我脑子里突然蹦出了那首歌:再见了我们的青春啊......,眼泪突然冲了出来,我不得不安慰自己,总是要结束的。
  彼时的我,刚刚工作一周,接到学校的通知,七月三号晚上就请假回到学校毕业。因为疫情,第一次回到学校,却也是最后一次了。回到阔别已久的校园,见到可爱的舍友们,大家的处境各不相同:有人工作了,有人要二战,有人还没毕业。星期一和星期二照例参加完各种活动,星期三本就可以离开了。但我实在是不愿意走,一直和舍友待到了周日。那天早上送完一个舍友,宿舍就只剩下了我和“胖儿子”两个人。磨蹭到下午三四点,我们两都知道,不得不走了,他要赶晚上的火车,我要回去上班。在学校的一周里,我总是想着哪天晚上静静地在学校里走走,似乎总是没有那种心情,也便和往常一样待在宿舍,有记忆的是周六晚上,对面的宿舍楼有人十二点多还在唱歌。
  大三的一天早上,我朦胧中听到楼道里面高年级即将毕业离校的学生在互相道别,我便想到我到那时候会是什么样子,心里感到一阵难受,又接着睡觉了。大概不会想到,大四最后一个学期,我只在学校待了一周。
  我没有总结过我的大学生活,但我毫不掩饰我对他的爱,自由而真实。从踏进大学的那一刻起,我就知道总有一天我会离开。就像我望着家乡门前的马路,马路前的稻田,稻田远处的树林,树梢上即将隐去的太阳,我知道我以后可能不会待在这里,所以我努力使他们留在我的脑海里,努力避免人类总是失去了才懂得珍惜的毛病。早上上课老是打盹儿、想看的书图书馆总是没有、期末考试总是在突击复习、晚上散步不小心打扰了情侣接吻、意外认识了失恋的心碎女孩、爬了五岳的华山和嵩山......,每个人提起大学大概都会有很多好玩的事。
  那是自由和满足的时光,那是青春和成长的时光。
  一年前,大家升学了、工作了、二战了、延毕了......
  一年后,大家读研了、工作了、跳槽了、毕业了......
  最后分享首歌:https://c.y.qq.com/base/fcgi-bin/u?__=phjtWE

  我那亲爱的朋友
  你是否不能停留
  你常感叹时间飞快
  昨天还在
  转眼未来已到来
  无论怎样的未来
  有些事不能更改
  就像你在风雨面前
  从不后退
  只会为爱而流泪
  请你不要胆怯 善良的人
  在黑夜里我陪你
  你看天边的光 或暗或明
  却从未熄灭

  

❌
❌