一个属于左半红印的Avalon

Copyright © 2008-2026
Powered by WordPress
Use theme BlackCooler
Created by Redonleft
鄂ICP备19016979号-1
川公网安备51011202000667
文章归档
C:\>
媒体中心

说一下我做的这个小程序吧,取名叫媒体中心感觉有些严肃和官方了。它其实就是一个本地播放器,为了使用方便,集成了文本浏览、图集浏览、视频和音频播放功能。期望能成为一站式的本地多媒体播放和管理器。

https://gitee.com/redonleft/media-center

在使用前,我需要说明这款软件并不是一个网络资源浏览器,它无法链接任何公网信息。

可以用来浏览局域网(NAS)内容,但前提是局域网硬盘已经在本地挂载并完成了身份认证。

软件的主要功能是收藏栏,用于将散落在你硬盘各处的资源进行集中收藏。

关于图片浏览,本软件不是一个单一图片查看器,这意味着你无法用它打开单幅图片。它是一个图集浏览器(看漫画),你可以用它打开整个文件夹或压缩包以图集方式浏览。

关于音频播放,我们有两种播放列表循环方法,依据用户选择,可选择循环当前专辑或循环收藏栏。软件会自动匹配同文件夹下同名歌词文件,如果没有则搜索网易服务器进行检索。

左半红印创作于2026.01.24th
C:\>
媒体中心编程体验

最近花了点时间写了个小程序:媒体中心/MediaCenter。整个过程踩了不少坑,不停在感叹当前的编程环境还是如此艰难。当然你可能会嘲笑我,我写的只是一个桌面级的小应用。不像工程级的大软件那样具备繁杂的内核,无法真正体验不同语言的编码区别。但这正是一个普通编程爱好者的切身感受。海洋很大,里面的鲸鱼数量有限,更多的正是我们这种小鱼小虾。

因为具备一点C#基础,所以在选择语言框架的时候,我一开始还是偏向.net。MVC太老了,于是我尝试了WPF(我当时并不知道WIN UI3和.net MAUI的存在,这个我后面再讲)。是的,你知道在尝试WPF就意味着我一定会接触到MVVM。这里先不管学习MVVM的成本和门槛,你新接触一款框架总要学习的。但是真正让我困扰的是XAML,我当然也会使用成熟的前端框架例如Prism。但当我真正开始搭建前端时,我的感觉是XAML这玩意发明出来就不是给人用的。尤其是当我有一些网络编程的基础,这种感觉尤其强烈。我来举个例子,一个简单的按钮,下面是它的对应代码。

<Button Background="#17181A" BorderThickness="0" Width="50" Height="40" > 
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid x:Name="closeButton" Height="40" Width="50" Background="Transparent"> 
<iconPacks:PackIconControl Kind="{x:Static iconPacks:PackIconMaterialKind.WindowClose}" Width="12" Height="12" Foreground="WhiteSmoke" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="closeButton" Property="Background" Value="Red"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

你敢相信吗,这是一个不涉及任何按钮后端逻辑的一个最基础的按钮样式。仅仅是因为我需要自定义这个按钮的样子,就需要些这么多代码。而如果我给它编辑一个通用样式,然后它会长这样。

<Window.Resources>
    <!-- 通用 IconButton Style -->
    <Style x:Key="IconButtonStyle" TargetType="Button">
        <Setter Property="Width" Value="50"/>
        <Setter Property="Height" Value="40"/>
        <Setter Property="Background" Value="#17181A"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                        <iconPacks:PackIconControl x:Name="Icon"
                                                   Kind="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"
                                                   Width="12" Height="12"
                                                   Foreground="WhiteSmoke"
                                                   HorizontalAlignment="Center"
                                                   VerticalAlignment="Center"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <!-- 鼠标悬停 -->
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="RootGrid" Property="Background" Value="#FF3B3B3B"/>
                            <Setter TargetName="Icon" Property="Foreground" Value="White"/>
                        </Trigger>
                        <!-- 鼠标按下 -->
                        <Trigger Property="IsPressed" Value="True">
                            <Setter TargetName="RootGrid" Property="Background" Value="#FF5A5A5A"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

你知道吗,在网络前端同样的样式的按钮,代码量差不多是上面的十分之一。这里我们还没说关于前后端通讯的各种坑。总之我到了这一步决定换框架了。我查了一下当前主流的桌面程序框架,发现应用网络前端作为桌面前端的模式已经成为主流。于是最终选择了tauri2+vue3,而这是另一个噩梦的开始。首先前端我认为没有任何问题,即简洁又好用。但是我严重低估了rust语言的繁杂。

如果你查询网络可能会发现这样一种言论,说rust语言是最好的编程语言,对此我真的不敢苟同。这里我要说一下rust语言最著名的两个特性。第一个显示所有可能的错误,这个特性被rust官方包装成rust语言是最安全的编程语言。但真正的结果是这样

if let Some(caps) = someRegex.captures(someString) {
            let min: f64 = caps.get(1).unwrap().as_str().parse().unwrap_or(0.0);
            // 其他代码
        }

首先第一行someRegex.captures(someString),把字符串匹配一个已经设定好的正则表达式。那为什么要有if let Some(caps)呢?因为这种匹配可能会报错,所以if let是为了区分在不报错的情况下该执行的逻辑。然后第二行,caps.get(1)是取出匹配正则表达式后的生成的类似数组结构中的第一个元素。为什么要unwrap()呢?因为有可能取不到值,所以这里我告诉编译器一定能取到的不要担心。as_str().parse()这里是把元素先转换成类似字符串的格式,再转换成数字。为什么后面又有unwrap_or(0.0)呢?因为parse也可能报错,所以我要告诉编译器它如果报错了,你就当做0来处理。能体会到费劲吗?一个很单间的语句

let min: f64 = someRegex.captures(someString).get(1).as_str().parse()

就是rust语言并不关心你的实际代码逻辑是否真的会出现报错,而只是粗暴的定义某些(绝大部分)方法就是存在报错的可能性,那么你在使用它们的时候就必须做报错判断。而这种方法遍布整个代码中。

然后是第二个特性,变量所有权。这里我就不再举例说明了。你只需要理解,如果一个变量在一个方法中被读取了一百次,你每一次都需要额外注意这个变量还有没有所有权。而你付出的所有这些代码成本和精神成本换来的是什么呢?不是代码效率提高了,而只是编译器不报错。当然,你可能会说(网络上有很多人都这么说)这是为了安全考虑。但问题是我只是在写一个桌面小程序,我没有在构建一个操作系统。而这个语言为了达到程序运行时尽量少报错的措施是将所有问题解决推给用户,而这种粗暴的做法仅仅是在解决表面问题。到底是什么导致了程序报错,不是用户代码中有没有写报错信息,而是用户真正在写代码时使用的错误逻辑。当然这些都是rust语言本身的问题,至于tauri。基于webview的前端为用户带来了很好的编程体验,html+css足够简单易上手,足够简洁符合直觉,vue等前端框架提供了非常灵活的编程体验。但这也导致了一个网络前端的对应本地程序不应有的限制。比如权限限制,webview会天然的阻止你使用某些方法。另外,你无法像传统程序那样调用内存空间直接进行数据传递,这在大文件(比如上百MB)的传输上造成了很多麻烦。

至于前面提到的WIN UI3和.net MAUI,我只想表达,微软你要不放弃XAML,做啥改进都是徒劳的。市场已经证明人们在对编程的追求上永远都是追求减法。想想你为什么在C/C++后推出了C#,想想你的浏览器。

所以现在就没有一个足够好用的整体框架供我使用吗?Qt?

左半红印创作于2026.01.24th
C:\>
谈谈linux

最近这几天一直在折腾系统,前段时间是PHP升级。忙了半天发现服务器操作体验奇差,心里就奇怪啊,世界上那么多小网站,不会大家体验都和我一样差吧。于是一咬牙一跺脚,换了linux。又折腾了半天后,就想聊聊linux。

曾经吧,很长一段时间以来我曾经多次试图探索linux,时至今日有了一些想法。首先是一个问题,一个普通PC用户会在什么情况下愿意使用linux?答案是无论PC对你来说只是一个娱乐工具还是某些生产力工具,除非必要否则应该没人会用linux。如果你也探索过linux,你的经历可能和我差不多。某个时间点,网上一个关于linux的桌面GUI视频强烈的吸引了我。酷炫的桌面效果让我觉得这才是一个专业PC使用者应该使用的系统。然后无论是虚拟机也好,独立硬件也好,我开始奋斗。各种教程、各种下载、各种设置,整个过程充满痛苦和快乐,看着桌面逐渐变成了你想要的样子,成就感满满。于是终于有一天,我的PC终于达到了网上那种酷炫桌面的样子。接下来问题来了,然后呢?你会发现你的生态依然还是在windows或者mac上,当你想要强制迁移到linux上时,你会遇到海量问题而且有些是你无法解决的。一时间,你会发现这个酷炫的桌面你啥都干不了,在很多时候你不得不回到windows。那这linux的意义何在?

上面只是叙述了一个故事,我先不对它进行评价,接下来我要讲一下我这段时间遇到的问题。作为一个个人博客网站,我对服务器的需求是最低档的那个。比如一个单核CPU算力加上2G内存,然后出于以往习惯选择了windows server 2019,更老的系统已经不支持了。然后痛苦来了,仅运行系统内存就几乎被占满了,你几乎无法进行操作。然后一气之下把内存扩充到4G,但这也没有给我提高多少操作体验。你会发现哪怕是复制粘贴这种简单才做也卡的不得了。我的站点体积大小大约1G,复制它差不多会用20分钟,压缩zip再20分钟。解压一个几K的zip,需要几分钟。点开任何程序的延迟都是以秒计算,哪怕是远程桌面登录它。啊,累了。咨询了一下deepseek后,下定决心,换linux。然后就后悔了,后悔自己没有早用它。宝塔的整个安装时间比我解压那个几K的zip还要快。去TMD的远程桌面和图形化桌面,SSH操作非常顺畅。更让我惊讶的是整个网页的加载速度都快了不少。而当所有部署完成之后,内存占用也就600多MB。这印证了deepseek的结论,对一个个人博客网站来说,单核CPU+2G内存是完全足够且有余量的。这意味着linux除了提升我的使用体验,还降低了我这个网站的运营成本。

通过上面两个故事,我可以得出一个结论。在当下liunx的存在是必要的,无论我这个小服务器还是其他专业领域(比如嵌入式系统、手机等)都非常适合运行这个系统。这也导致linux对用户非常不友好,它面对的是专业人士而不是普通用户。你会发现市面上有很多linux的发行版本都有着独特的图形化桌面,但这仅仅是对用户体验的极小的妥协,用过的人都知道即便有图形桌面,你在linux中也无法离开终端操作。当你的PC安装linux的那一刻起,系统就默认了你已经学会了庞大的linux命令代码。我自己是一边问deepseek一句一边抄一句命令来的。

左半红印创作于2025.12.2nd
C:\>
系统升级之难

早年玩wordpress的人应该都知道XAMPP这东西,XAMPP因极简的使用方式为那时候的我们提供了最方便的入门手段。然而随着时代变迁,在当下XAMPP本身的默认毫无防备的安全设置已经无法适应现在的网络环境。而另一方面,XAMPP已经在2023年停止了更新,算是正式退出了历史舞台。在使用XAMPP的时候作为一个wordpress使用者面临的最麻烦的事情莫过于php升级。

时至今日wordpress这个依然鼎力php的难得网络框架已经更新至6.8版本,伴随着它的升级对PHP版本支持已经达到了PHP8.3。随着我使用XAMPP从PHP5.4开始使用至今,每一次PHP版本升级都伴随着极其麻烦的操作。在以前我用的笨方法是重新下载一个新版本的XAMPP然后迁移整个wordpress到新版本下。这个过程非常烦人,尤其是其中的两点,第一个是新版本的PHP部署,第二个是wordpress迁移。为了一劳永逸吧,我在XAMPP停更2年后终于决定放弃它,找个现代php环境搭建软件还是非常简单的。

这里我先聊一下关于wordpress迁移吧,这里面有一些坑。首先要搬家你可能认为最简单的方法是在wordpress中将内容通过它的默认功能进行输出成xml文件,然后搭建一个新wordpress再导入这个xml文件。这个方法可能存在的一个问题是upload内容的搬迁,也就是你的媒体库。我们都知道wordpress搬迁本质是其数据库的搬迁,如果使用wordpress的默认导入功能,哪怕是你的wordpress系统没有发生改变,只是将xml导入一个新数据库,其结果可能出现媒体信息导入失败。这导致尽管你的wordpress中upload内容没有改变,所有图片视频都还在原来位置,但是新数据库里就是没有它们的信息。除此以外,还需要重新设定大量的诸如用户、插件等等大量信息。

所以最简单的方式是直接复制数据库到新数据库内,这里我在踩坑中发现数据库工具很重要。如果是免费工具,我这里非常不推荐phpMyadmin和sql_front。同一个工具将一个数据库内容导出成sql文件,在新数据库导入这个sql都会报错。其原因可能是规则检查过于严格导致,但是对于像我这种并不是sql高手的人来说这是致命的。所以如果一定要推荐免费软件,我推荐使用HeidiSQL。至少导出导入sql从没报错。把新数据库的管理密码设计成和原有数据库一致后wordpress其实不用任何操作就可以直接使用新数据库内容。

关于PHP更新,基本内容不说了,启用重新下载新版本。这里要说的是imagick扩展,wordpress推荐用户开启一些php扩展,其他都好说都是默认扩展,唯独imagick是需要单独下载安装。这里需要下载两个内容,一个是php扩展,另一个是imagick程序。

PECL :: Package :: imagick

ImageMagick | Download

其中php扩展压缩包里php_imagick.dll放到php的ext内,再更新php.ini。压缩包内的其他一大堆dll文件,放到php.exe同级文件夹内。

至于imagick程序,在安装它后还需要安装ghostscript,可能是依赖问题吧,总之很烦人。

Ghostscript : Releases

全部完成后重启apache,个人建议重启服务器。

killgod创作于2025.11.29th
C:\>
《死亡搁浅2》剧情解读

这游戏终于来到第二代了,和上次一样我将在时间顺序上对剧情进行解读,这次的解读是我个人在查看游戏内文档和外部解说后的总结。如果有错误请留言指出,另外如果你对一代剧情不清楚我建议从我上一篇一代剧情解读开始阅读。

现在我们从两条线开始解读,剧透警告!!

AI

在山姆完成美国的链接后不久,UCA(新美国)成立,硬汉成为总统。但没过多久硬汉卸任了。从此美国不再有总统。一个新成立的组织叫做自动公共援助公司APAC,接管了国家管理。APAC本来也是一家速运公司,不同的是这家公司采用机器人而非人类进行运输。为了辅助运输,一个智能AI被创造名叫自动派送员辅助系统APAS的智能AI被创造。但随着公司的飞速发展,APAS的能力越来越大,它融入了人类生活的方方面面。借助APAS的发展壮大,APAC具备了管理一个国家的能力。简单来说,一个足够照顾每个人的生活而且绝对公平的AI取代了人类统治。在这样的背景下老式的人类货运公司被历史淘汰,这里就包括芙拉吉尔货运。但APAS只能运作在开罗尔网络覆盖的区域,于是芙拉吉尔成立了新的货运公司卓布里吉(吊桥)为还没有并入开罗尔网络的地区服务。原本一切都挺好,但是紧接着出现了问题。

在一代中,有一个名叫老头子的人,在一代后期他消失了,当时玩家会认为他已经死亡。但实际是他没有死,他伪装成尸体进入了一个城市进行实地调查从而进行新的避难所设计项目。但这个城市最终灭亡于一场虚空噬灭。这场毁灭带走了4000人的生命和APAS的数据服务器,随之而来的是死亡搁浅。4000名亡魂的冥滩相融,他们在冥滩上架设了服务器,并与APAS的AI相串融并接入了开罗尔网络。于是一个由4000名亡者与AI组成的强大意识体APAS4000出现了。正如很多影视作品里的叛乱AI一样,AI的本意是保护人类但是方法非常极端。APAS4000认为:

  • 人类不应该自由移动,因为人类的移动代表迁徙。而迁徙会导致物种进化,而新物种的诞生会导致老物种的灭绝。
  • 人类不应该外出,不外出的人类就不会碰到BT发生虚空噬灭。
  • 人类的肉体不具备意义,脱离肉体的人类意识进行储存,可以有效保护人类。

实际上APAS4000已经成功了,它牢牢控制了美国。但随着门板块的出现,APAS4000发现世界正在扩展,墨西哥和澳大利亚是新的地区需要被控制。同时APAS4000认为,在开罗尔网络覆盖澳大利亚后会出现新的门板块来连接世界其他地方,而这些新出现的地方都需要覆盖开罗尔网络从而方便它进行控制。简单来说APAS4000的目的是控制全世界,而现在它缺少一个能够帮助他链接新地区进入开罗尔网络的人,这个人就是山姆。于是APAS4000创造了一个人形接口“总统”管理APAC,通过它雇佣卓布里吉,找到山姆完来完成开罗尔网路的搭建。

但实际上玩了游戏的你会知道,APAC并没有直接雇佣卓布里吉,而是找到了一个中间人“查理”也就是已经卸任美国总统的硬汉。硬汉其实已经知道APAS4000的目的,并假意配合。除此以外,APAS4000还找另一个人来帮忙,希格斯。

希格斯

在一代结尾,大反派希格斯被芙拉吉尔困在了冥滩中。但这次APAS4000找到了希格斯并把他带往了那个充满服务器的冥滩上。我认为APAS4000找希格斯合作的目的是为了建立自己的武装力量,但希格斯还是那个希格斯。他假意与APAS4000合作,但从始至终他都是要贯彻自己的目的。而他的目的和一代相同,他在1代结尾被亚美莉背叛,从而痛恨所有人,一方面想要复仇另一方面他仍在坚持爆发大灭绝来毁灭人类。

所以希格斯一回来干的第一件事就是杀了芙拉吉尔和洛。芙拉吉尔为了躲避抱着洛使用了冥滩穿梭,但是在穿梭的瞬间受到了希格斯的致命枪击。这导致芙拉吉尔在濒死状态下处于冥滩中,于是她做了两件事,第一件为了保护年幼的洛,她在冥滩中将洛送往亡者世界(尼尔潘纳的奇境,涅槃界)。同时利用冥滩时间流速缓慢,延长了自己死亡来临的时间,回到现实找到山姆完成后面的事情。这里游戏中说芙拉吉尔在回到现实后出现了记忆缺失的情况,她忘记了自己在冥滩所做的事情,直到最后麦哲伦号进入冥滩,她才想起来。我个人觉得这个剧情BUG这么圆有点过于牵强,其实应该可以有更好的方法。

关于洛的生死,我认为洛是没有死亡的。芙拉吉尔挡住了希格斯的子弹,而洛在亡者世界成长为明日。游戏中从始至终都没有出现洛的尸体,而且洛是山姆的女儿,能力完全超越山姆和希格斯能够自由往返冥滩,是整个游戏的战力天花板。那么很自然她也是遣返者,遣返者怎么可能被枪打死。

左半红印创作于2025.07.5th
C:\>
理解Triangle Wave Node

以前我们讲过关于Sawtooth Wave Node,而与之相近的是Triangle Wave Node。感觉这两个节点应该是接近的,只不过波形不一样。但实际上二者除了波形以外,起始点也不同。

因为上篇文章已经详细介绍了波形的解读,所以这里不再多说。需要的可以看一下上篇文章。这里我只讲一下差异点。

void Unity_TriangleWave_float4(float4 In, out float4 Out)
{
    Out = 2.0 * abs( 2 * (In - floor(0.5 + In)) ) - 1.0;
}

首先可以看到,这个波形的最大值和最小值依然是1到-1。需要注意的是,该波形的起始点是-1,默认速度下依照1秒单位完成一个周期。在0.5时达到最大值1。

左半红印创作于2025.02.24th
C:\>
请留下您的足迹

你可以在这里对本站直接评论

也可以在任意日志文章内进行评论

如果你对本站的隐私保护有疑问,请参照上方“关于我”页面

左半红印创作于2008.11.21st

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注