前言 LG虽然是大厂，但是显示器DDC/CL却无法设置输入源。声音亮度等设置却没有问题，这是我目前最想要的功能。我有两个系统，共用两个显示器，不想买二进二出KVM切换器。国内这些KVM也就是个能用的程度。高刷和EDID几乎没有，就算有也不是所有接口都支持。 所以我有个想法，让系统来通过显示器DDC/CI控制切换，我再买个USB二进二出切换器，共用键盘和鼠标。写个程序监听USB设备，插入就通过电脑执行DDC/CI切换显示器输入源。 这样比KVM二进二出切换器多了很多优点： 少了连根视频线 显示器和主机直连兼容性更好 USB切换器便宜 支持高刷等显示器特性（EDID的话我目前切换没有乱桌面布局，我不确定） 我的两台显示器，一台是AOC，好多年了，DDC/CI没有任何问题。还有台LG 27GP95RP，这两年入的，DDC/CL能控制大部分功能，唯独输入源控制不了。国内LG DDC/CI相关讨论都很少，国外还是有讨论关于LG显示器DDC/CI的问题。 开搞 DDC/CI不支持，国外有大佬通过GPU来控制显示器切换。我不太懂，你可以看看这篇文章。虽然里面只列出少部分LG显示器型号，但是自己试试说不定也支持，27GP95RP上面就没有列出，但是确实可行。 先上输入源代码，其实很好区分，你先确定你的LG显示器有什么接口，例如两个HDMI和一个DP，HDMI就是0x90开始递增，DP接口就是0xD0递增，至于type-c就要自己找找了，应该是通过0xD0来递增，我这台显示器没有。 Input Source Value MONITOR_AUTO 0x0 MONITOR_DP1 0xD0 MONITOR_DP2 0xD1 MONITOR_DP3 0xD2 MONITOR_USB_C 0xD2 MONITOR_HDMI1 0x90 MONITOR_HDMI2 0x91 英伟达显卡可以通过NVapi-write-value-to-monitor项目来执行输入源切换。 你只需要修改两个参数，第一个参数0来选择显示器的序号，第二个参数是显示器的输入源（这里是切换到HDMI1，你要修改成自己想切换的输入源，看上面代码）。后面的0xF4 0x50不能动。我的是AMD显卡，具体显示器序号和他功能可以去项目里看作者的说明。 writeValueToDisplay.exe 0 0x90 0xF4 0x50 ADM显示可以通过amdddc-windows项目来执行输入源切换。可以执行文件在issue中找到，作者上传的txt文件，下载下来修改后缀exe即可。 先通过detect命令来查看显示器位置： amdddc-windows.exe detect 我这里适配器索引5，LG显示器是0，要切换的端口DP1 0xD0。你只用修改最后三个参数。下面通过命令来切换输入源到DP1接口： amdddc-windows.exe --i2c-source-addr 0x50 setvcp 5 0 0xD0 intel可以看看这个issue MAC OS mac os可以使用BetterDisplay或者m1ddc来控制，同一个作者。m1ddc我在M4 pro上使用过了没用，不管是不是LG显示器都无法切换，没有做过多研究。 BetterDisplay没有问题，但是发现了一个坑。如果使用扩展坞带的视频接口，那么大概率是残血DDC/CI，或者干脆不支持的。网上资料说是由于usb占用了两个引脚，导致功能残缺。我这边是发现不能切换，但可以调亮度和声音，这还是另一台支持DDC/CI切换输入源的显示上测试的。所以要转视频接口建议买质量好的type-C直接转HDMP或者DP，不要附带其他扩展接口。LG用HDMI直连所有功能都正常。 BetterDisplayLG显示器输入源：DisplayPort 1: 208, DisplayPort 2: 209, HDMI 1: 144, HDMI 2: 145, USB-C / DP 3: 210。CLI文档可以看文档。 显示器设备名称 UUID等信息去APP中可以看到，命令行的话看文档找找。 除了namelike，还有name uuid都可以指定显示器，ddcAlt就是输入源端口代码了。非LG显示器切换去掉两个参数Alt字母就好了--ddc=15 --vcp=inputSelect。 /Applications/BetterDisplay.app/Contents/MacOS/BetterDisplay set --namelike=ABC --ddcAlt=208 --vcp=inputSelectAlt 如果安装了betterdisplaycli可以简化命令，但是BetterDisplay不仅要装，还要启动，否则不行： betterdisplaycli set --namelike=ABC --ddcAlt=0x91 --vcp=inputSelectAlt Linux 我就是ddcutil的issues中找到windows切换LG输入源的，没有Linux需求，没有尝试，命令行参数对着上面的改。 -d就是显示器顺序号，x0090就是输入源端口代码，其他不动。 ddcutil -d 1 setvcp xF4 x0090 --i2c-source-addr=x50 --noverify 顺便把DDL/CI代码也贴一下好了： Input Source Value VGA-1 1 VGA-2 2 DVI-1 3 DVI-2 4 Composite video 1 5 Composite video 2 6 S-Video-1 7 S-Video-2 8 Tuner-1 9 Tuner-2 10 Tuner-3 11 Component video (YPrPb/YCrCb) 1 12 Component video (YPrPb/YCrCb) 2 13 Component video (YPrPb/YCrCb) 3 14 DisplayPort-1 15 DisplayPort-2 16 HDMI-1 17 HDMI-2 18 USB-C 27 DDC/CL切换用winddcutil或者ControlMyMonitor都行。 winddcutil查看显示2的60 输入源可能值，ControlMyMonitor有时候不准。 .\winddcutil.exe capabilities 2 (prot(monitor)type(LCD)model(U2790PQU)cmds(01 02 03 07 0C E3 F3)vcp(02 04 05 08 0C 10 12 14(01 05 06 08 0B) 16 18 1A 52 60(0F 11 12 ) 86(01 02 05 0B 0C 0D 0E 0F 10 11 12 13 14) AC AE B2 B6 C6 C8 CA CC(01 02 03 04 05 06 07 09 0A 0B 0D 0E 12 14 16 1E) D6(01 04 05) DC(00 0B 0C 0D 0E 0F 10) DF ED FF)mswhql(1)asset_eep(40)mccs_ver(2.2)) 60(0F 11 12 ) 代表十进制15 17 18,对应DP1、HDMI1、HDMI2 DDC/CI切换就要简单些，setvcp和/SetValue后面分别是 显示器、输入源切换代码不变、显示器输入源端口，可以看上面DDL/CI代码来尝试切换。 .\ControlMyMonitor.exe /SetValue "\\.\DISPLAY2\Monitor0" 60 17 或 .\winddcutil.exe setvcp 1 0x60 17 结语 好了，差不多就这么多，看起来不复杂，但是找资料确实花了我好几个小时。 下面我就要开始写代码通过USB切换器来同时控制显示器切换了。目前已经在windows上成功，另一个系统还在路上。等都到齐了我再来多测测，到时候再分享出来! 2025-03-04 切换搞定了，效果不错，通过USB扩展坞代替KVM切换显示器输入源
前言 最近倒腾Java，发现JVM并行收集器在还有大量堆内存的时候就开始触发老年代的回收，通过GC日志发现每小时都会执行GC和Full GC回收，回收是通过System.gc()调用。 那每小时都调用一次Full GC，我添加启动参数-Xms11g -Xmx11g分配11G堆内存只是为了好看吗？每次Full GC耗时在600ms，并行收集器老年代内存使用还不足5%，真是发神经了！ 过程就不做记录了，无聊又蛋疼。以下是在使用了RMI或者其他NIO对象的情况。 RMI DGC每小时触发一次Full GC 原因：DGC代码中调用System.gc()导致并行收集器触发Full GC。 解决办法： 修改DGC调用System.gc()执行时间，默认一小时，单位ms。启动参数添加： -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 禁止程序中的System.gc()，添加启动参数： -XX:+DisableExplicitGC 使用支持并发的收集器（CMS、G1、ZGC或Shenandoah），并且添加启动参数： -XX:+ExplicitGCInvokesConcurrent 方法1，治标不治本，延长时间触发Full GC会导致STW时间更长，可以配合并行收集器使用-XX:+ExplicitGCInvokesConcurrent来控制频率。 方法3，启用-XX:+ExplicitGCInvokesConcurrent参数可以尝试在垃圾收集时使用并发收集来减少STW时间，从而提高应用程序的响应性。 不建议使用-XX:+DisableExplicitGC来限制System.gc()。 因为从Java 7开始，Java提供了基于NIO的RMI实现，称为NIO-based RMI。这种实现利用了NIO的非阻塞I/O模型，能够更高效地处理大量的并发连接，减少了线程资源的消耗，并提高了性能和可伸缩性。通过使用NIO，NIO-based RMI能够更好地适应高并发和大规模的网络通信场景。 DirectByteBuffer是一种在堆外内存中分配的ByteBuffer，它与NIO密切相关，因为它可以直接映射到操作系统的内存中，从而避免了在Java堆和本地内存之间进行复制。在NIO编程中，使用DirectByteBuffer可以提高I/O操作的性能和效率，特别是在处理大量数据时。在基于NIO的RMI实现中，使用NioServerSocketChannel和NioEventLoopGroup通常涉及到DirectByteBuffer的使用。 虽然 DirectByteBuffer 对象本身是由 JVM 管理的，它们存储在 Java 堆内存中，但是 DirectByteBuffer 对象所持有的实际数据存储在堆外内存中。 JVM 通过 DirectByteBuffer 对象来管理对堆外内存的访问和操作。当 DirectByteBuffer 对象被垃圾回收时，它所持有的堆外内存也会随之被释放。 因此，触发 Full GC 通常是为了回收已经失去引用的 DirectByteBuffer 对象，进而释放掉它们所占用的堆外内存。 Full GC 在回收过程中会扫描整个堆内存，包括其中的对象和引用。当发现 DirectByteBuffer 对象已经没有引用指向时，JVM 就会将其标记为可回收， 待下次 Full GC 执行时进行回收。这样，间接地通过 Full GC 回收了 DirectByteBuffer 对象，也就释放了相应的堆外内存。 如果禁用了System.gc()，那么不会及时的清理 DirectByteBuffer 或者其他 NIO 对象导致堆外内存也不会释放。虽然最后也可能因为JVM堆内内存不足触发Full GC 来释放，但没必要冒险。参阅 监控程序调用System.gc()堆栈 可以使用 async-profiler 跟踪System.gc调用者： 预先开始分析： profiler.sh start -e java.lang.System.gc <pid> 发生一种或多种System.gc情况后，停止分析并打印堆栈跟踪： --- Execution profile --- Total samples : 6 Frame buffer usage : 0.0007% --- 4 calls (66.67%), 4 samples [ 0] java.lang.System.gc [ 1] java.nio.Bits.reserveMemory [ 2] java.nio.DirectByteBuffer.<init> [ 3] java.nio.ByteBuffer.allocateDirect [ 4] Allocate.main --- 2 calls (33.33%), 2 samples [ 0] java.lang.System.gc [ 1] sun.misc.GC$Daemon.run 在上面的示例中，System.gc从两个地方调用了 6 次。这两种情况都是 JDK 内部强制进行垃圾回收的典型情况。第一个来自java.nio.Bits.reserveMemory.当没有足够的可用内存来分配新的直接 ByteBuffer 时（由于-XX:MaxDirectMemorySize限制）， JDK 会强制进行 Full GC 回收无法访问的直接 ByteBuffer。 第二个来自 GC Daemon 线程。这由 Java RMI 运行时定期调用。例如，如果您使用 JMX 远程，则每小时自动启用一次定期 GC。 这可以 通过-Dsun.rmi.dgc.client.gcInterval系统属性进行调整。 结语 起初我很不明白为什么DGC代码里面会有System.gc()，我一直以为堆外内存不归JVM管理，那调用System.gc()又有什么用呢？又是问ChatGPT又是各种搜索，才发现虽然JVM不管理堆外内存，但是管理使用堆外内存的对象，System.gc()是为了及时释放掉不再使用的堆外内存持有对象，堆内释放了，操作系统就会释放堆外内存了！
探索ChatGPT、NewBing和Google Bard：我与大型语言模型的初体验
前言 最近ChatGPT很火爆，不过我还是近几天才知道，平时也没怎么看新闻，有点孤陋寡闻了！既然都发布了那我也来试试看人工智能到底有多智能！这不，一口气体验三款AI，chatGP、Bing AI，还有Google Bard。 一个ChatGPT出来，后面就会有千千万万个ChatGPT如脱缰野马般涌现，那么那些跟趋势蹭流量的ChatGPT到底是人工智能还是"人工智障"？ 注册ChatGPT 刚接触到ChatGPT那就不得不提注册了。虽然注册也没什么难点，但是还是有限制，例如你的IP、手机号码等。当然伟大的国人总是能想到各种方法来解决问题。 IP问题科学上网就行了，我还是推荐多使用欧美地区节点，香港都不行，和大陆一视同仁了，唉~~~！ 注册也没什么难点，主要是短信验证，对号码有要求，国内、香港的反正是不行的，只能用其他国家。电话验证接码我使用的是sms-activate 【链接包含我的Ref,介意的话不要点击】，当然有很多选择，这个倒是无所谓。openai好像也只是用来验证你是真人，也没看见那里能设置或修改电话，目前来说应该是没有什么其他用途。 sms-activate必须要充值后才能使用，充值支持支付宝、银联卡等。 点击右上角充值： 选择支付宝即可，当然也可以用银联卡，什么方便用什么： 充值完了就可以选号码开始注册了，在右边搜索openai： 选择印度尼西亚（你可以试试其他的，但是不保证能收到验证码，没收到码一般也不会扣费），一般在openai验证手机号时等个3-5分钟，如果还没有接收到验证码，就可以X掉再换一个号码了，没收到验证码是会把扣费返还的： 他们甚至都为其出了官方教程：sms-activate注册openAI。 注册openai后就可以正常使用了，chatGPT-web版是免费的。听说是有次数限制的，这两天使用还是没有触碰到上限。 体验ChatGPT chatGPT-web版在对话中经常出现错误的情况，之前我以为是访问人数太多导致，这两天换了一个相对稳定的翻墙节点后稳定许多，否则会一直出错，需要刷新网页才能恢复，非常难受。 ChatGPT自然语言处理非常出色，精通多国语言，非常流利。最让人惊讶的是上下文关联，每次对话都会结合本轮对话上下文做出回答。 打个比方，你先问它"乔布斯是谁"，再问它"他对苹果公司有什么贡献"，这里的【他】是指我上一次问题里面的"乔布斯"。别小看了上下文关联以为很简单，其实对于提取上下文里面与本次对话有关联的关键词是非常困难的。这就类似于人类的记忆功能，你和刚会说话的小朋友对话时，他就可能经常出现"丢失上下文关联"，不理解你说的是指什么。 它甚至都能写论文、诗词、程序，在编程开发中，遇到BUG、异常它都能给出可能涉及的问题。这可比在搜索引擎里面一个个翻找答案的效率可快多了。何况中文垃圾站真是一片一片的，大大降低效率。提供给它的任何日志，让它总结分析，它都说得头头是道，有理有据。这确实在某些情况下对我有很大的帮助。 目前网上也出现了很多Chrome浏览器的ChatGPT扩展，总体来说体验还是不够好。 一些基于web获取chatGPT-web版的Cookie和Token，在chatGPT-web版中对话都经常断线要刷新网页才能继续，放到扩展中也一样断线，体验非常不好。 还有一种基于OpenAI-API，这种体验非常好，但是OpenAI-API收费。目前注册ChatGPT账号有5美金的体验金，而OpenAI-API的收费是按照字数来收取的，称之为Token，以下是价格： 关于token消耗，以下引用ChatGPT3.5回答： 在 OpenAI API 中，每个模型的 Token 数量限制是不同的，因此“1,000 tokens 约等于 750 个单词”这个说法的具体计算方式也可能因模型而异。一般来说，这种说法是根据一个平均单词长度为五个字符的假设得出的。在这种情况下，一个包含 1,000 个 Token 的输入文本大约包含 200 个单词。而根据英语写作的经验，每个单词的平均长度约为 4-6 个字符，因此约 200 个单词的文本约有 750 到 1,200 个字符，这就是通常将 1,000 个 Token 与 750 个单词联系起来的原因。但需要注意的是，这只是一个大致的估计，并不适用于所有情况。 这个token是双向计费，你提问的字数和AI回答的字数都是会消耗掉token的（包括标点符号等一系列其他符号）。虽然GPT3.5 1000Token只需要0.002美金，但是1000Token消耗非常快，特别是中文字符。如果使用上下文关联，需要用到会话ID，那本次对话所关联的会话也会再算一次token，你想想这个消耗有多大。个人使用都能感觉到肉疼，但是公开使用那就更不用说了。你看现在网上大把的免翻墙免费用ChatGPT的那些，如果真是ChatGPT API搭建，然后免费给你用，你觉得现在还有这种"好心人"吗？如果不是ChatGPT，那它是个什么东西相信大家都应该想得到！ 目前我在使用的Chrome浏览器扩展只有一款，chatGPTBox，相对于其他的体验比较好，而且开源。目前划词功能、配合搜索引擎比较实用，其他的我觉得也还好，使用情况不多。有兴趣可以点进去看看。 ChatGPT还有Plus版，可以抢先体验新功能，目前plus版可以使用GPT4： 我目前还没有去体验Plus版，chatGPT-web版使用的比较少，但是我准备使用openAI API，所以弄了张美国虚拟信用卡用来绑定。目前国内推荐的虚拟信用卡大多都是depay和nobepay。免费版在高峰期会提示We're experiencing exceptionally high demand. Please hang tight as we work on scaling our systems.，需要刷新网页更频繁，plus应该会好许多，但是我没用过也不能确定。 起初我想使用depay，无奈连个像样的官网都没有，注册也有BUG，我发送验证码始终没有反应。而且充值有点麻烦。有手续费、月费、不想实名需要10美金卡费。 nobepay注册需要邀请码，这个邀请码自己上网找找，我也是网上找的 （989B08，用不了的话自己上网找找吧），没有还注册不了。 需要实名认证，注册时微信ID那一栏一定要已经实名认证的微信，到时候充值和实名认证都是要用该微信。 注册时最低充值500RMB，支付宝充值有1%手续费，开卡有手续费和最低充值金额（每张卡可能不一样）。充值的RMB，开卡是扣费也要选择RMB账户，汇率偏高，我开卡时汇率时6.8，他那边显示7.0！556766卡段开卡要充值最低30美金，需要扣除手续费、开卡费、汇率转换差不多2.X美金。556766卡段能绑定openai，开卡时地址找找美国免税州地址，网上搜搜美国地址生成器，生成一个即可，信用卡姓名可自定义。 openai使用的是Stripe收款，开卡时需要注意，你的ip最好是信用卡开卡国的，否则大概率被拒绝。如果你使用nobepay 556766卡段，选美国节点去绑定，一般是没有什么问题的。 目前支持卡段（已验证）： OpenAI/ChatGPT Plus 支持的卡段： 591393 （ DePay ） 556766 （ NobePay ） OpenAI/ChatGPT Plus 不支持的信用卡： 国内招行 VISA/MASTERCARD 、全币卡 全球付香港虚拟卡 万里汇香港虚拟卡 绑定成功后一般是从信用卡 PENDING 5美金，然后每月有账单，用多少扣多少！先用后付。 体验NEW BING Bing在众多搜索引擎中一直不怎么起眼，毕竟Google才是大头。虽然Google搜索引擎早已涉及自然语言AI领域，但是却是微软的Bing AI先出来。 微软在早期忽略搜索引擎，自家的IE也是爱用不用的态度，直到Google的出现，无论是搜索引擎还是浏览器，那个曾经有巨大优势的微软反应过来才发现已经被人家甩得太远。而微软近几年的操作一直在布局，从收购Github，组建Azure云服务, 投资OpenAI实验室，直到今天ChatGPT，微软在AI领域已经走在了前面。 Bing AI相对于ChatGPT最大的优势就是拥有互联网能力，目前的Bing AI使用GPT4模型，并且结合自家搜索引擎能更快更好的找到答案。Google虽然借助自然语言处理来完善搜索引擎，但是返回的大量搜索结果中去找答案还是非常耗时的，而Bing AI却已经缩短了从搜索结果中到找到答案之间的时间，这让Google搜索引擎感受到了压力。 在和Bing AI对话时发现，对于已知问题它会直接给你答案，未知问题，它会通过搜索引擎去结果中总结答案。可惜也需要科学上网才能使用。总体体验相对于chatGPT-web版反应稍慢，有可能时因为使用GPT4模型的关系。 Bing AI必须使用自家的Edge浏览器，不过可以通过修改请求User Agent来模拟Edge。Chrome浏览器可以使用ModHeader扩展来修改： Edge浏览器user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57 你甚至可以添加X-Forwarded-For头部然后指定国外IP来免除科学上网，但毕竟不是长久之计。 Bing AI虽然可以联网进行搜索，但是表现起来比ChatGPT要呆，很多时候一直给出重复答案，就算你强调关键字也是如此，甚至它会结束当前对话，脾气还不小。像是给它一份报告，让它分析，他就完全不如ChatGPT那样会给出总结和分析。看来Bing AI可能被屏蔽某些功能。 体验Google Bard 其实，我还是很看好Google的Bard AI，用了这么多年Google搜索引擎，Google搜索引擎的关键词纠错能力还是很亮眼的。我相信很多人在打字输入比较快的的时候，容易出现很多谐音词，当它输入到Google的搜索引擎的时候，你会发现基本上已经被Google纠错，并且在搜索引擎结果上面返回已经纠正的关键词，你是不是要找 xxxxx，红色高亮。ChatGPT和Bing也是有纠错能力的，只是我更想试试Bard。 2023-04-05 我已经获得了Bard AI的体验资格，很遗憾，它目前支持英文... Bard它说它支持关键词纠错，并且善于互联网搜索（我英语一塌糊度，这都是我用Google翻译的...） 你甚至可以将文章链接丢给它，它去帮你分析总结。我先是发生文章地址让它帮我做SEO优化，然后让它分析总结这篇文章。但是我发现它的回答有些问题，我把我这篇文章丢给它分析，它把New Bing说成是Google Ai的新搜索引擎... 当然它的中文还在训练中，这都可以理解。 Bard回复体验不像ChatGPT和Bing两个AI，它是一次返回全部答案，而其他两个是一个个字输出。Bard什么都敢说，什么都敢答，只要你敢问！ 有时候回答能明显比之前回答慢，我估计它是自己在互联网搜索，并且分析搜索结果。Bard虽然自己说会用到各种搜索引擎，但是我认为它多数时候都是使用Google，毕竟是自家的，不可能放着自家世界上最大的搜索引擎不用，去用其他搜索引擎。配合Google搜索引擎简直如虎添翼，这也让我更看好Bard未来的发展。 我立即去问Bard来验证，果不其然它回答确实优先使用Google，但是他这回答总感觉有点王婆卖瓜的感觉... 随即我又问它出现的原因是不是因为ChatGPT，连Google两位创始人都回来了，虽然我也认为它的潜力很大，希望它自己的回答也不是在讲大话！ 就目前来看，它没有像chatGPT-web版一样频繁断线需要刷新网页，体验感稍微好点，但是它的中文还在训练中，不知道还要多久。没有发现禁止某些地区使用，只是体验需要申请。 结语 目前我已经简单体验了ChatGPT、Bing AI和Google的AI Bard。目前人类在人工智能领域已经走出了一大步，相信在人工智能的帮助下，进步会越来越快。openai API价格比较贵，就个人而言勉强能接受，但是如果用它来做公共服务前期投入还是比较大的。ChatGPT和Bing AI可能是两个完全不同的产品，Bing AI明显更偏向解决关于搜索类型问题，虽然基于GPT4，但表现出来连GPT3.5都不如（阿三的锅？）。而Google AI Bard虽然还没发布，但是消息模型功能上感觉比其他两款要强大，看看Bard的后续进展吧！ 我这两天只玩了下消息模型，还有很多图片、语音等模型还没机会，就拿图片模型来说，提取图片中的文字功能就可能绕过目前大部分简单图片验证码。 AI是新鲜事物，能力有限，目前最多也是辅助使用，远没有达到代替的程度。它无论是写代码，还是写论文，都基于大数据。 但这仅仅是目前...
前言 之前写过一篇文章Emby公益服-上万部电影电视剧免费看，如今账号快到期了，需要考核后才能延长账号有效期。正准备去考核时发现不是三天一次考核机会了，而是每日签到获取积分后才能考核，一次考核需要40积分，每日签到获取的积分不固定，好像1-5分都有！考核失败还是需要72小时后才能再次考试！ 这就有点蛋疼了，他们bot签到是需要回答问题验证的，之前好像没有。本想实现自动签到，就用telegram-cli试了一下，发现根本不支持内联键盘消息！！！毕竟好几年前的代码了，作者也没有在维护。那么现在只能找找其他的telegram client api集成包玩玩了！ 皇天不负有心人，找到了一个python包python-telegram，赶紧上手试试看支不支持内联键盘消息！ 开搞 python-telegram命名空间和python-telegram-bot有冲突，如果装了两者没法用。 有两种解决办法，要么卸载掉python-telegram-bot，要么使用virtualenv环境隔离。 python-telegram没办法在windows下使用，还不支持！ 先来将环境隔离,创建一个工作目录，然后在目录下安装隔离venv是隔离环境名称： mkdir python-telegram-client cd python-telegram-client virtualenv venv # 进入隔离环境 source venv/bin/activate # 安装python-telegram pip install python-telegram # 建个文件写代码 nano server.py 退出隔离环境使用: # 退出隔离环境 deactivate 安装python-telegram 在Github看了下作者的例子和文档，随便找了个试一试。tg.get_chats()返回的都是chat_id，找不到哪个chat_id对应的群组/bot。想了个办法，查看每个chat_id最后一条消息，然后自己一个个找： from telegram.client import Telegram import re,time ... tg = Telegram(...) tg.login() result = tg.get_chats() result.wait() if result.error: print(f'get chats error: {result.error_info}') else: print(f'chats: {result.update}') # 查看所有会话的最后一条消息，用来查找对应的chat_id chat_ids = result.update['chat_ids'] for chat_id in chat_ids: chat_history = tg.get_chat_history(chat_id=chat_id,limit=1) chat_history.wait() print(f'chat id:{chat_id},message:{chat_history.update["messages"][0]["content"]}\n') ... 找到了对应的chat_id就可以和签到bot交互了。在发送签到命令之前，还需要监听新消息： tg.add_update_handler('updateNewMessage', send_verification_code) def send_verification_code(update): # 所有的新消息都会被监听，增加判断只监听自己感兴趣的 if 123456789 == update['message']['chat_id']: # print(update) # 提取问题并且计算 question = update['message']['content']['text']['text'] print(question) a = re.findall(r"\s\s(.+?)\+", question, re.M) b = re.findall(r"\+(.+?)=", question, re.M) if a and b: print(a, b) c = int(a[-1].strip()) + int(b[-1].strip()) answers = update['message']['reply_markup']['rows'][0] print(f'{a} + {b} = {c}') # 用答案和内联键盘值做匹配，一旦匹配执行按钮点击效果 for answer in answers: print(f'答案：{answer["text"]}') if int(answer['text']) == c: payload = { '@type': 'callbackQueryPayloadData', 'data': answer['type']['data'], ##每一个内联键盘都带有data数据 } # 发送答案（点击内联键盘） result = tg.call_method(method_name='getCallbackQueryAnswer', params={'chat_id': update['message']['chat_id'], 'message_id': update['message']['id'], 'payload': payload}) result.wait() if result.error: print(f'getCallbackQueryAnswer error: {result.error_info}') else: print(f'getCallbackQueryAnswer: {result.update}') break 以下是签到验证内联键盘消息部分报文： ... 'content': {'@type': 'messageText', 'text': {'@type': 'formattedText', 'text': '签到需要确认问题并选择您认为正确的答案：\n\n25 + 1 = ?\n\n请在 30 秒内作答', 'entities': [{'@type': 'textEntity', 'offset': 22, 'length': 10, 'type': {'@type': 'textEntityTypeBold'}}, {'@type': 'textEntity', 'offset': 37, 'length': 2, 'type': {'@type': 'textEntityTypeBold'}}]}}, 'reply_markup': {'@type': 'replyMarkupInlineKeyboard', 'rows': [ [ {'@type': 'inlineKeyboardButton', 'text': '26', 'type': {'@type': 'inlineKeyboardButtonTypeCallback', 'data': 'Y2hlY2tpbi1RbWFYT3Z5SzlKb0VMZmtmUURMN3ZYcVZMeFIxNk1CRQ=='}}, {'@type': 'inlineKeyboardButton', 'text': '22', 'type': {'@type': 'inlineKeyboardButtonTypeCallback', 'data': 'Y2hlY2tpbi1PVkdOSjliZTJncXgxdDdmQTFQdnc5b2RtTXoxNlJ4WA=='}}, {'@type': 'inlineKeyboardButton', 'text': '85', 'type': {'@type': 'inlineKeyboardButtonTypeCallback', 'data': 'Y2hlY2tpbi1EV1gwTDYxTzRvWmxqRjFmYTlkMThBcFZ4OW1ZbmR5Sg=='}}, {'@type': 'inlineKeyboardButton', 'text': '66', 'type': {'@type': 'inlineKeyboardButtonTypeCallback', 'data': 'Y2hlY2tpbi1WR05KOWJlMmdxeEUxaTdmQTFQdnc5b2RtTXoxNlJ4WA=='}}, {'@type': 'inlineKeyboardButton', 'text': '68', 'type': {'@type': 'inlineKeyboardButtonTypeCallback', 'data': 'Y2hlY2tpbi1sNUJrbVBOd1hxQnhWZnpmMmJBUVZMclFKN0RSOXlqeA=='}}]]}}} 最后发送签到命令： result = tg.send_message( chat_id=123456789, ##chat_id自己找一找，虽然都一样！ text="/checkin", ) result.wait() tg.idle() 这就完成了一个账号的签到，如果是多个账号使用tg.idle()就不行了，tg.idle()会堵塞当前进程，需要终止信号终止。要跑多个账号只能等待一段时候后自动停止，然后再执行下一个账号。需要修改下代码，让他可以跑多个账号： accounts = ['+123456789', '+456789123', '+789456123' ...] for account in accounts: tg = Telegram(... phone=account, ...) tg.add_update_handler('updateNewMessage', send_verification_code) tg.login() ... print(f'当前账号：{account}') print(f'等待15秒，接收签到验证信息并且验证签到') time.sleep(15) tg.stop() python-telegram是支持多账户的，会保存用户凭证，所以登陆一次即可，新账户登陆还是需要输入验证码的。 现在我们将他打包成可执行程序： pip install pyinstaller 打包 pyinstaller -F server.py 打包完成在dist文件夹下。 如果直接跑起来会报错：..../libtdjson.so的话可以下载作者编译好的libtdjson.so，也可以自己编译td build。libtdjson.so的位置可以在代码中指定: tg = Telegram(...,library_path='/path/to/libtdjson.so') 这时候退出隔离环境deactivate，跑一下../dist/server，没有其他问题的话加入crontab, 设定每天执行一次即可自动签到！ 结语 我个人感觉python-telegram在可编程上比telegram-cli要好用，之前LXK0301京东签到脚本-自动提交互助码一文中使用telegram-cli虽然也可以达到效果，但是不如直接敲代码来得舒服。telegram-cli更多的还是作为一个linux的telegram客户端。 python-telegram用来做签到只是个引子，更多的还是各种自动化非常简单了，毕竟官方提供了所有API。本来以为要自己集成实现API，还好有大佬做好了！
前言 阿里云活动，限量 Linux X Hands-on Labs T恤免费领，参与linux实验并答题送T恤！！！ 开搞 活动6月1-10号 获取路径： 访问 https://summit.aliyun.com/hol 体验馆-《Linux命令入门》 体验Linux场景，通过10道测试题 拿90分，T恤 Get 点击开始体验，实例创建完成，然后直接结束体验，再点击再次体验，再结束就可以开始做下一个任务了。 每天凌晨刷新200件，上午11点刷新300件好像是这样的，听说8-9号每天1000件。 可以先完成所有任务包括考试，等到刷新T恤后直接领取，领取要填写姓名，手机和收货地址 T恤有码，活动后统一收集！ 考试答案 题目都一样，只是顺序可能不同。 1，下面哪个命令可以用于删除文件而无需确认 B A. rm B. rm -f C.del D.remove 2,下面哪个命令可以获取到当前工作目录的绝对路径 B A.passwd B.pwd C.whereis D.whois 3,下面哪条命令可以把f1.tst 复制为f2.txt? C A. cp f1.txt | f2.txt B.cat f1.txt | f2.txt C.cat f1.txt > f2.txt D. copy f1.txt | f1.txt 4,为了让文件的所有者有读（r）和写｛w｝的权限，而其他用户只能进行只读访问，权限应设置为 C A.566 B.655 C.644 D.744 5,在vim 编辑器中的命令模式下,键入( )可以光标当前所在行下添加一新行 A A.o B.p C.i D.a 6.在ps命令中，哪个参数可以用来 显示所有用户的进程？ A A.a B.b C.u D.x 7，如何在文件中查找显示所有以“*”开头的行？ D A. find \* file B.wc -l * < file C.grep -n * file D.grep '^\*' file (多选)8,下面哪些命令可以看到文件的大小？ ACD (D选项存疑 自行判断) A.wc B.df C.du D.state (多选)9,Linux下用哪些命令可以在管道统计一个文件中单词出现的次数？ABD A.grep B.wc C.find D.awk (多选)10,下面哪些命令可以停止sshd服务？ ABD A.ps -ef | grep sshd | xargs kill -9 B.killall sshd C.kill -9 sshd D.pidof sshd |xargs kill -9 结语 赶紧去撸羊毛吧！！！
前言 《侠盗猎车手5》（Grand Theft Auto V）从昨晚11:00开始免费领取了，昨晚官方站点已爆炸，直接500错误。今天缓解很多，可以正常领取了。活动截止到5月21日。 领取 领取地址 领取时最好不要用代理，如果IP领取次数太多可能会出现您的账户目前无法下载更多的免费游戏。epic对同一IP申请的游戏数量进行了限制（您单独的IP是绝对不会达到这个限制的），加速器可能会使大量用户使用同一IP，造成无法下载更多免费游戏，建议遇到这个问题的玩家尝试更改自己的IP 免费的东西总有很多人批量领取，然后你懂的。风气太差了，哎不想多说。 正在下载，游戏真的大！！！
前言 找到一部分jetbrains学生包领取码，分享给大家。500个学生包(让你爽一年jetbrains全家桶)，领完就没了。 使用 登陆你的jetbrains账号，然后拼接链接https://www.jetbrains.com/shop/eform/students/request?code=加上下面的code,在登陆的浏览器打开链接，下面是500个学生包code: a1ys9j11ho0gznptueydc7kmo 1fn11mctn5o3w77cdxwvij5m6 a9pjjx1ommm33sh617xymejqw 70gm6f47o654e42xdt7gi3sw5 8kcz8nk8nrg1ez1fit1fxhejh 71znawiuth942frbm9hxl4z9s 6onm2yttj081k5mgf91ajj859 1u7rmph8e9h79luuwi6avnvqz 575jycq0lsghaxauvgqdyof5l 1z2sicdpclrpasss7w8mezxcd 3inceny3o2q5jvl7gnv9ivvc4 aaw0gdgweac8v4jz6wgtdqbho cxrilafk5w7dwobsrsj98ekoa de1cdyyk5coq6n18l9sg478ix dk5rfrtlbnu8gu32rrrkfz46y 2n2l0jqserhoxnvqp748nh9cc 752sxb43wlv6kpwtrcdmc9oig bbj4kvxlvcsv0957ch58xn8s4 551ofkn5oo1llgbkxxyiuecq5 ezm1em2doh7vcdh21m58sf2vj 22f7yf06b0ldxwqh84qgezoli dvamfusy9mvoqnbxsg15iz2xb 6wdxb6y0bx2deh1ij5blibhuu 88ph0ndl9vcrcoc5qzzv1hefx 8bfcl789ysy4g7vcqt4qix89n egu0rp627hn3pm8r8b4e9abn3 43myqmm80ya1qs4wwl29wkavk 1ir72n12u0818sptofcgx918u 4gui8p7di4h3wf9jngk4metvc cg62hrmqdr62q05ivea3cprhv 2l27ea99qqby8q7wk4iwi4we 65da9zpk5v6qgm5i6lveu5hbi 858qf7psg85n0f9jnziyq0v9d 5qjpiy3j5ch7bj28x7l1op8ew 2dy0uime2wp7b1a2jns4onlob a9eejeco8ella0dyzknnwdfif e9icd3z8xg6fwtr322h3wlozf 2e164sqay2k42je7gxlqzzi11 21k7ar53iqd5m7uf95rqh4rpb 4g1cv00mzb6i19eiaztgiae7g aifpm0qihnmektz7ixbwg2hkb 3rw3ack62cdjxjik3hl14x0jd 49ta0025b7xen7uzseh6hwm4o 5ptf61mvs920kl9424buof3ib 8hnpopzktzk2x9smqetiup1hb flwu756j3eng7t08jj5ba4jo 6izv80ko8ob0ub2swp2kt7hn1 57j0zroy21mvmts3u9jdsdiv7 5996f0mnu313qhi8cs67a7iux 8t2t3y27m2xsyn3qo1ayg1agp edgqnqpeuff432gobfo9yi98q bpqeedqn3g05rdonvfwnx53pg bha7vhm7obl2mitx8mr9ca02u dwsggvft4srp2043erf7lqsxh 1bt9op8mdbe8yvvfk2661p5gw 4eaz7cd8f6eif555z0cxra7o0 8g13tt42kz8xeibz76czqo26q mcxieql6bgz2z64b9y2zyszj 8ynpqwf0zhcwwynqhhfsm72c9 1t70tzll100rwjwytqml3gurt 32fg6el0okwgr9jdlazy78rvv dj6aj2638mase96n0nm1l7f7h 4rkv6xoafvy4oxgodl4z8k466 65pu9fbnsx3cauig826mh92he avuao8jvriardzjyscohgdl5a bvulstsxcvlfyzxsdsa9bglqp 5mmvssxj68t4fom98m76e9q9g tq9h731emxu8bj4ghvxd8ckx 2jkffukbvx39uk9hw8g2dug9q 13y66c3h1dxlxgj9f8u4xinua 71a40maqjsnvgidtihsabshf9 a7ghifeu14xs56bn9tsw32qvf 46d421bv69f25zyy0bo7gvtm2 cds86t50qy0c3vd3c6e86ocva 6ia9ctlr4rpg5necl4c8xuj42 65vbqj9xh3uckay102ohzi6x9 b4t8f5kiqlod3a1gyusfv0hej 210ltg5lt6xva8u4yrvq7b9rm 67itw48x2bermtek4a0wz3akk cc70400dng6mvo416s7kn54ie 636lksxeqdy8pzzrytoupsbhk dw6d69xgpx7s4vlibws74dg9q d7snq55iu52x7u0uofoyhz7mq 7cg94ong6cjnsjn1z5wj0e745 9cvas6eiu6bborb9l7amnedyt vp2n0iskt8ssexrprkxctxkp 4gvpv023bwopk5o6e4m8ofefg 5t36otvgd92v72c2gmpk9x7x3 48ar905nfzooeh65u4d7vrpz6 cjk0udxkidou5r2ly9csl6l9y 7ttt9omwx7unw64cp0cvetufl 44qre7zqh6dylbbcdcos0clyj 172135jehftcije2sf69q36sw 70ou9w1eeetm3f5824pgovdzt 62m3amr2ezo6ci9oh6hc1cuqz 9q98usyypvdopi9hsvg7ta9gn 6jv9p85wwxp0slzbpu5vdqrdj bzy3nk8cq7jdk4zm3k09tjpp6 907a65synhz4clqrnpr5abuok 16evb5eq2c481zapmdhxqu7xt dthzdxkgy39mhr4yxfh1i09u7 42fqa4w37h6stdtco76htj2v0 3wm5uxjcsv7nmps34apsugn42 6tvdsno543rahhbll13ljhkwm 1diymr6kdqd951qct3vsho1m6 b7g6g1b98ibnoa6rh208e4wjs c44cckhqup3cpi537wtnvqn1e 8y0sdjx1kuv5orx2b3y9hs2xr 5e4lk0s87vh79zgaal4ydqc4l 7yr8gx7drzknky3wx14r6npxe zq2o40p57d5jb1f2aqex9fta 2zrrqy06y72gv1z65mpb0zohg bb05yheqk7aus2jotd7xvrj5w eqsggefmxonra8xaz1wa5luz1 41ibj1o17droy698ro9u3mcu0 3zuhxu1od7q8snrdh62gd1qdy 31kmrd3q7so0neu0a3km4zitm b9dbv4fpggxrb7rx75ixbycu6 6qzunx0oy2zb9ldavceh1f6al bhdjpmtcdr8972itslcbirvor emfg4d9w0zvsq536t1wnk03tg b073f115pd45j86bthgu53s8p aslr0ivqmcd9bfb5gl5val7h9 2vvthdvnuj4qe8n7ox0q5es8a 20a0sa8ad8ja3s194pbt4nfgy 1e6qclo1qnzhdbft1b50if6t3 4lx1hwsqcoim2zw0i7u9h42py ejax44s5p0lqypunlmbhypfu bvu8gp95e1419ed1ph59123bn 8ztsxgguf5bgliksqtwxlmuz2 1ccxtf0iqs7wzbrqyvb8matjo aj6rzl56qu8qoknwtp0npgwvx bwtdyggkx5txe72chtvp7s3c ntncswqozls41p4k79wiy4pz 851a3kzpa6lmgaleuslu3t94h cvbr5b5ckv0dp2grpyjye2zec 8naq9rd3gxv0531nbyl88yfm0 5z1qlbq1qk2lj4tae96wb4s72 5099hdcn02lilpp59g3ay9rlt eydrkpq7hfv330yc0768l6u43 6bd2vvw2rvkq39t2bdgaacj5i b7jdg339jcetu3ggalsjjpmu5 avcgx6or0p5dfsl02eqyk4fsz 2fgl1izsodnsxpvemwvrz9dri dudg69lzzcnnijt09c5n571lc 4p672xoulhls3wu7kw0db365w 396pp48igvrjrag34pcou8c6s 6x6u4tbt8ygdphos03bg4wr4v 1q410gvqb716i7xzbuk3tpqif 4ukvfgavggfcqw4fmc9xykj8k kqkqjxfd7qhsik852jb9lmwl 86evjcgsz67scmr3p3pszujge b1383debllopietw07gum02nu 14bf5cj9xvbj0bqtmv7tmtshn 4epzzj2yijx36rp09bk9gocby 4sfqbzy4t7eg7mc622ddj4j6j 4v3bvykjtk4a9igtwqg6crngi 3rkg9fm3p9d6dqazy7mp87ldv 1452o399ulgekroz155mxjv2 mbrum25jqrv4d8rt7y828fes eb1eq48ws6s6727va5e2pqe83 44ae38lft8e9uoostutfeoaf2 8s4ejc7qh6h5g3ked50y0hknc 1dg9cfgz1f32yq1r85ahp9m91 53aj9h12d6cwn9leagt1t1kfx 665smsbk4tyuj6zujjqgbk72j egeg1j2k03vccadjit81w33l3 12pqv962bpwgnj7jjtk67o6vm ex57kvw9ftonbqfg735lrunri 5r2y58tuza8i3i46bzh2yu15e beftz7pxsl419ony8m7lef34b edav9gnyyi3tx0jswknukhe25 59szyzhspjmiaeynyoztwaal5 1k5qpvvc8xuymm9lzkzjbsxf5 anoll8k3sep3lkd5dg8q9uwd eajo5gy1u4tzwza39x1bhrut9 3qi6xdgza4m04jis0k3x8eev2 fn5vuocq3xfpmc61t49dfin4 dm9lxognqpisedi76uuou1jcc 97fe2tfdk0yfd0o42a3n1dl2l cqcl05br4vhcsm2tqv9badxtf 38bltii1m9jym329g93sqpkia 80rqul6ocprxmee2skffe2b6c c0j101805d0gbtg7s4xi8advi 19o8nq2zzu94q8l4i9miet8z8 bnkkfyeykv4t63xfy0wmy352k w0cqsm5twphjxi1la60cw5ga 4bygvwxvywxgxoedggg3hgafz 5cpaic6uxicn7oixfk2ia51ad cvp32bc3vi2kcbzwlbr8addu9 6hcmzzru4wmhtuczc8fwcfa4 dzg301g3uemf4wtzmxw9ttnwt 47r8jr01fz3taldqqpgby8aud 8ayevxq67ess0di9tzli527ag djp93d2zcgbzbzju4u17nx11x 12m5o1s15owzcxz6kopmx4roy 63oar10rccelbmz4w2e1nr3mi 1pbjzi1kmqprkwckfermkjyr8 6y5alezj47cti453w93bxrzk 2fihtyo754w2peoqdn11h13v5 10w52i1h3zrkbha0zwd4yshri 9cy77ofzr97sueuwczic6a2oo 12zlagt3l5gba82hhaqgzj482 3r3xi1jzpsz78iwv9vi0kesbi be5gnh4l2td2d44hhvrfwnwvo bw50nh8ca01gmorp3vw6dajtg ehglyxuwr9dr4twprvqxsbvw4 9w1u1tksxcelv2u6eepm0ql1l dplr9bw2ysjirzzcbpylrt2m9 7cpn3zqpdsup4twonshcyw8rh ekbmzrwbkv0h1hmrgloph1fla cvedj63zzx8yd40qy4ileqjhw 8ybidwxixdnoctnzr2gjrrlbb cciemiizalj6hrb1ntbdr6yq2 crvcyh5zl51tytn6cqtn11h6f e9t41pqy4d8eerh2bhs4wazec d7z53lg5ftlqzumrobq02din 7z3raqetqxgfgs8a6vmlbjpx1 eh635578cs82427u5rwdpmwnz bkpqedgfc9hfhjjc0g5inzs8l 1tywjw1gcjianj4d984rs3uyr 7dcus27vp3wmr3uptjm42kx1s 4pbfvnxuvs56ajxjsr73kxp35 a73nee2zxjmznwt42ercozmeq 94ogie2v6po71yn5azxituin6 ec9vi249qtbuizr153j7sn67h ao7sw7ip4ain6yb7x2otyebi6 c07sskia6brjpg924rfsxl6ja 999x3ecp64ee4z0ehslpoxb2r 34nik9ouvlyhgmihc75jfwz54 alr6s9yl0lwnv7j7o8vy1zbjk 91yo99o3r45epnonea1go66ee bpbyrnr37g0wlprifnixl7x84 7nnprg99lwj155ya4jyax4b27 80nptpf2vua2dj32pmbcq9u4 es8cjagwamdkm1utfzpgr3e5h aa96lnuum088x2zmzi9x95nqh ey485dm2zdpk81axgbitd55vn 4r5aahlxa4ghqhuvkeyyxdsl1 1hnnrjgcxfhwpi4168wb7qc4o 1rm5mieelpumnk9yx3q60j926 7vmz76tiyeh9hkel6dk394vdu 88rfrc1ibnjdknovttezgchm3 c1dhzw40lf0119dwmkl91zo3r ahdnk89nglgxurl5ja6u89xyo 4t8jkmhoet983zh4zfnazicmp 2ssul0lo64uj6rz50ajxg1fmh 40labewa808b4krderzspnrcx 42i78x99sjbrn2nxmrjd6dmul 45m3czoaaz46ldjw9m9n1ywv1 982vq5jzrod3oj3p3fg7d9kmp 4d59taxdtf3ik**uqtjvg0b1 7ch57im09h0ug5nduundd6wwx cn6bqsy4jz5iuxho7rgwpclov eiw0nxverf7wsznyc01dm2rwy 12vy5yok1k7bvhlbeoreqlzxj 2gky2gi8f25h5epythbyi92q0 c0vwwzu8d27r8eca2siqymcca 2a20z477jwwu5pw6zpp8yvxgi 36eo6436fktyn6unem4ar2l0b 925qbaw90v64tikbu5tl6o1be er7hrx64eaqgz13r5cjoh5kde c2677hyvjxcbmd9jf101fl386 3hlzb4b0k7kvemxpfpwao29dw 7vur6n2mz8ynzg3xk85rde1kg 8xm7sd2puv8pt7w0gzjm6883n aa3n7br1qbl78xgkl887oy80 1duucdri7oip1t29txwzgdssn eqpvgd501vxkf25bp0gyb4x5h 16suyms7ws89r3y2uqnv76vkj a83v66klg2c8fokpia99gg4ig 61vgll9osdqja0z5qhx1rlkse 1dh5m850luq788nv5lvjvui7w bch9hm9zx6n1lu5i6r2o5omba bl5jffhr7ytok9sn8f9gt2voh 8frhkt5vv3tuncmbjgfckx5zu 17ekeuw002hbeorl4e61uagza 8b34h8l88xuafnz05fh1bq79x d1e3z4eo9k1nzlkcd9edmhh9l 7bgbwtq0vujmyq29o6k5i8o4g 4glyhu0ffetmwa62nj4h1d9x9 31956p2mowvubzw3cvyhqjzi0 a32e0nahgqulrricarotsigra c5rnlzbn9vatd7ak3rx2lg72y 4q3s3q5i6p6ya0ckp3slubxgc dvzfeprnqug1zq6e2wol4xsy0 a58a6q7hm8jragcyl0c092zal c44f1khvcq5lp0tztg4wm7ea2 c3t4lmiimpd60l6hpp3jgdkqg cgwyazq7yvlqkssscs6awlv3u 8zruj1y8o4a2vlygap13gk4et 8iwhqnzczjbsq0c0999j1s8wh 5vigkqigbipffd6418gnt80gd ahotsny4ykdhmv3rhilqb8k6h dioxi6rk8ozmeyc7wryvteszv 7x0qbej4xjb580perumj9nlcj 9lxibxvvcx34gzwxyosnmhj5n 4bi5dxwiwctv5xjxqok1n3x09 9uhjjolej9fqiph12xyp5e00p c4j0wz3ixdo313r2ffco8srbe 1h987lxm1r1w6pr3yc0gsz3ip ds3t2t5kz2lc82zephf41c3b3 bibzbsnryc59rf0q3vdydj63x egjs0obnv1h8gee26fanvxw8b f1yo9d482l4a85m9kupm3emht 3pnj2xxqbdbf10sbll03x6wve afvamwfwmscoobt6gf0ovz5jm f14s9nq7lay90c8z959dcnty 1s5i3wg3i7n043qkzwer1by3a 4c8ejvcc1wqbikri8oeuaqysb co338b66qjivrptbepsz0c08m 7mldkuzr8vkrl3rk43441zg16 3sd02hjrcwjxl2xusydbx5vc1 31i47lnyaeu6wgypheqo3pwzd 5kishche3dwgrh4boutnz3d8s 2gv1tf4y0c16gdwmjwvfnpmew 49velndurayyspfuoy6cncrlq 30vhhi5fu8avf455qg95ezsok aaxdqive0unbnwoiy11fmhx6o 4t91ht0y5bmwyynmz5qhipnx 56u7bgbla0x32w0nfu7t4jv8z 9shhi9d4dgqkkrsjwqkladlqw duo7swzxu60vhnydjuie6vtbb 7akgfn8xkan3lcwayz8o141wo 3ug2pfdwicn905rwnnj0opepl 17i5xv2w7625d2p9r1ephlzgl 3cf1ruslqa7lt7mblpt5t2by0 1uaxuof6tujsnakrrqhv4gc6k 72hs3972da0cigcidfedbxdnw a9w2nuiloof59muuiacuvhe4b 6vk28kwma0b4d4edz41zqnksz 8i4b3v4k3vm67rj1u31iwicq8 eyp9m2ukg3541i69ktczg8bxi 1s29npl30faal3sx1g1rud9xo byts3bi0ashd40f8qihug2mfr efw4zpje3s65h7l7k0yv4rdii eo4t4aa9efe9p3g3dwkk12e0i 4mzqifwbdcaai3w1obcip27c1 ebnkecqgr9j7j4ktpq49961wf 3unjqfrfv5br6lqkw60xkukfa 5hfgkqb5eyzearg5h9fl3lqcb 4h0o6ta6en78osxcfp4r8qwma e0etx1b4q486gl485v0atb1uh adh01zyf08ia4tmpgiumi5fm5 1yjrzu3d0xxdnpinlob9rbc1l 66d1u2rl8pss6g4k1l8sb61m3 54t9snxzrysvphxa8fsfkh78a 8vjucis05k9j9knglgkdplfst 2236dyoequfn3klqkw7iu7xn9 8vsa0ta2airv7gtpfuhcrsb1 bjnrgmbc9xpp7r8oqe0rl863n 4xgvrca0zceeal2i91lwcyy96 oqydeeo1wx9w0h1mbvx1day1 7xy91bu21nxz172qrhgrn01rr 6tmle7x2o66obc75fl7y3awct 1caks9vr22btb470t20qyrjb3 7uh5jedeyblqamlnaxjqcnxzn a8lb4fztr1g52zl8xg2hj2alz c3xbtuh1rhbso3dx51h0lm2n 9ifk5bvct2trktyeo88coqbv 4ok5pixbffdyj9f900li5d07m 961terh0e8ipyueleniuslto3 7mdz77yx3tir86nc8xbnviy1u cmtdswut3bk6cn8sz2vkkb1ai bcgpn8cbycf9tkqhkv6y9yn0v 3ab5ni18y5bd8zdr72foiuvn5 2d9mp9jrbc93ttd7aph8ra32h 8lrslvsiygpssre08hz31uoid 6lwjv7ky8ht08374oe8es94ku bn1q83iz9tgduh1pslr82ojjc ab8pwz8w3ndlbkcg5q1tvypw4 c51rkuy2735o10m27515sash9 3c9vmqgn2uvnmatiqem4sbp22 d5uoykfcqfrjabmxp5oe3nujk 4xdbhrbixxpm8rsyilo49alga 4wmj46odsqrsbga1lzpghee8k 6zc9fcazrm3cu72z8z7trxxqn 1gu1ad88k4ali8td7qh5u8uuz azjeu2t9i6unuoeqcvx1v2li9 9axe8rv1ggjgzk3f3bmx07c88 bhkyyjwc33bvqautu41c7tplr ucmf8gpr1xkyqsdmbvdv9ulu 3rsgvmniutsly1fmuh5wo8nmu bkl8lpx711o8h0px4y13edb9h 4swvzmfrldcodersgy5j3e2xv c27aho4r9qdy9ecmnb4ja3nxz dnnnkw4svn1iele4nq1titmd9 42rjmab18tq5he1e2mvlc3mr5 d5fl67b04rsuxssl0awsb10q8 czeydcwmewr6xf4q8xmmjjdl5 dgyrmwqdcrds55feg62fjz96e gxfmtcdszg787b3y3t8xqqj3 327fg7wudceo7nkign6fbhfsy 5zwbw64swzits0z3xz0duk8y8 1ri8t74f797nzy75dmd4jl06s 80kmm7xia0y1frx6qfufvqw3w uv3m4nje8gyero8iidhghy33 2fdn60h8qq4n6dfm79ffji1wt 4cm1jpzqk4ydgsg5xodypdkfj ejpsd6davj2di1irvvtgrwyej 13w4o8046ev5i794zkpjwmv0u 3etqvhaxkthhhov4tdpkdg34j ecdv9lg5fq74a6ppkk1kgw05m u3i3pmahrv9a5eble2g7m6ku 9crmllkoomdjqne9u1umfe1e2 cpcocbpuect7t4i5tyt3swrfx 640el5d6u4mzk7zi2et0etmtv dc0dc7gqz5rxfqwlrhkx1uz9j 77re3oqv9jygowbe51nzr2ime 296zgefacz2ctae4ggy6im5ge vkjjfty7q71knjvd108ifbf0 6otvuxc2gkaj2z7abjq3eg6wp 9wwj7acfleqb08r5tp3g0z4k baac45w53i6fyu8jdoccop7k5 5fcprf3apbvv29i5w9ah0xdna 3qzkj3pwgp5fagb379t6p1rc2 chpbhihfkaposwpvwh4o44nqi 7sfwmcev6utmom3pkjagnb30s 4zigt23edivik37xq06ztpgph 541q14oly9b9s97a33vthz274 3svhdavtlma9xz0ag5flzeq64 d8sc6bo0mf9jcya9gl9qggz79 asg6yxxk7ozlqza7s04vfo456 av5xy88kwrdo3orvnybzhdiq9 a5zxptqj5qhcu32rtb16meem0 ehot8e1k7uaa0ybv5zhyzi8uo 7mdit3dkxb3xmr015dph7ubk8 30chg9fjlzmeiyb3rhfhd0rct 5q0y0c4y2eh6an51ys4k8vf2d 1vviccpxltp0iy7xjm2dmyo81 17ad429ogoqgplrwitqp5n0uo 3bxct227tyoapn7zg6dhygke3 12zchcgtj6hwupe8ug5odg207 e674df6mytv50vp0y1ty54hb6 b4rntonleum4jcen5vbuhob5b 4shtodz2g4oy5jv0l3113erpo djpuiawhg5erjm5wdzm7144nq 8fek5rtcmw9f8cijsuwi8c8lx 2hgmz0naaxx49yvc9sdqftqqj 4zk2lkfylyg95m1vgdhqhv1xf bs1ix4ifg54flbx2ep20kg9bt 27omr37rjs2wmd528spluep2i 44jow559auwkw7f31ymiia9z0 cgmokrwre2dp7567gde3hmz0b 4wpr027bvo6rmlcw99t5xifmv 72n988hdv3avwq5p1w4sploya 3b1l9nm8p11cliry9atxpslaq 4wbqp5n1dxd400lzwj5027fqb a8f8l5b0fdqzea86b5pejk4r4 7xmsgdptim5rzv659uo3u1soy 1ut35s8n3gch3s2u8n92po9xa 62gau6g56l4tk0z9kvradrj3d ckrtaslxjos9na3mwq7m46twb 1c9u1caw1ujchllkveq2oggm0 2i9horgp2hw9ywqm3xr8p4xlw 1hqq0pponbhkr1ced6wiiwstx 957k81updxije0zdm2m4p79rb dvdhbiusuhl7g5i5zfshv7v1f 26b8sr3ufn0n91dpixvql9prd 9ungr2hzx1hjoyykja1m9bkq2 3z5bk43oyn1pi02txxc76d7vh 6int508q42sz8l0elb74ocmlc 83a1m7kz3v8uw2m4j2gy3xwkl 6tqpkrnweda0m1kq0yn3n2wbj a4a83l411ffw3bt1hfnrurzup aufetm82g2el984pdrwq4vvlc 2gpfzy3ava40rvvdvd6cg1q8c e6ccyrsu5j1sa70qgo00fvl8x 1cu8cik5q22uhjii9zt6qvfqh 5g5pnn1r2t4ck3oz5p23ialyd e0xby9sknm28cb4p9dqcgk98h 2h90h8yn2s3k5aifm4quu69x3 71v6zldr2is8qyv8jvg0kynj8 8d6vtz9i9xw8jjlv02u0ueys0 7tsjqcbxu209qqg3bsz5loy4n 36dk4h8xp5uj6yw7hz6uxrm1o exnfs8e6y2jj5xa8w980wlvlc 2keyfnsso3g5v14lm12x0elec dbvfu3ud577r4jfwlj320wwb0 95ogfluh1izz0hqdtn24pjfq0 cqgyaydiunyr20ycd0bekkj5o 6xe7m8w8qsht5llhvmhzioydp 6b46ghava2q4oxbjwwxapi1xt 7dnbcgig61md966vsxwkr7zs6 dgci7uiae3gyv4qeiem0ary87 dwu36p3sx66uv9goc6a5z6fix 2dc7r4yqjpxr3w51jm25uu0xi 5y6er5gz31jia4wl6x12dz0q9 2x067vvk9n4xsayk4p849fn1w 6jiln85xesx3nmufzvnbc92yx 4hz7ontepmqvkrkrfllekt3ix otx7omf73czm2q8w4idmrygq 5a1fbz5axqo98yxuifnef240t 3pslpvafjxr0hf02r9xg3nskl 5xxkq6bjqk385gs2e8vmf0z61 9smokkesa5jpysb7u8jbgw3rq cmo8i802p8fa6162x38txdxlr 33pzs6gfsth9p5kma5x7dvo2a e4vxudaxxq499ngi7e0ue80a0 4ocrx9k7r4fmmhgu9b9snb7ax
前言 两种后台管理扩展我都使用过，两个扩展既有很多相似点，却又有很多不同。接触过laravel nova之后，再接触laravel admin有种莫名的熟悉感，发现在开发中有很多类似的设计思路。 接触laravel admin时间只有一个来月，时间还不长，随便写写吧。有不足之处还请多多指教。 感受 其实laravel nova就是laravel admin的进化版，显然laravel admin是开源扩展，而laravel nova是付费使用的（99刀一个授权可不便宜），在这不考量两者使用授权方面。 laravel admin是一个中国开发者，做出这样的扩展确实非常了不起。扩展设计合理，但是优化上没有laravel nova那么好。 其实最开始接触laravel nova之前是考虑过laravel admin的，由于laravel admin已经封装好了权限管理，自己替换处理又相对麻烦（其实就是懒），才放弃的。laravel admin的权限管理没有做缓存处理，每次使用都要从数据库查询，其实完全可以缓存起来减轻数据库压力。相对于laravel nova这个功能已经交给开发者实现（我还写过一篇关于 laravel nova 权限管理 的文章）。类似于这样需要缓存的还有菜单功能，因为网站上线后这些几乎不变的的数据却又频繁读取，缓存能解决不少数据库压力（有时间自己处理下）。 laravel admin模板还是使用HTML(对于我这种前端弱的一逼的程序员来说真是非常友好)，而laravel nova使用vue.js,相对来说vue.js体验感更好，但是技术要求也相对较高。折腾vue.js多多少少还是要翻几次文档。在扩展字段的时候前端模板就相当重要了（反正我写的CSS无法直视）。 laravel admin更加符合国人操作习惯，我使用admin LTE开发过几个后台，基本上不需要教如何使用，大多数功能、按钮一目了然。而laravel nova很多功能、按钮藏的比较深，很多同事反映过找不到地方... 在代码层面，laravel admin我总感觉没有laravel nova那么简洁、灵活。列表页，详情页，编辑页总共需要些三个不同的模板，我是用laravel localization本地化功能，所以需要将三个模板全部修改翻译，而laravel nova只需要编写一次模板，不需要在某个页面显示的字段可以单独关闭： //laravel admin 列表页、详情页、表单,其实还需要三个控制器动作分别输出不同的模板 /** * Make a grid builder. * * @return Grid */ protected function grid() { $grid = new Grid(new ProductSpecification); $this->gridViewPermission($grid); $grid->id('Id')->sortable(); $grid->name(trans('product/specification.name'))->sortable(); $grid->created_at(trans('admin.created_at'))->sortable(); $grid->updated_at(trans('admin.updated_at'))->sortable(); return $grid; } /** * Make a show builder. * * @param mixed $id * @return Show */ protected function detail($id) { $show = new Show(ProductSpecification::findOrFail($id)); $this->showViewPermission($show); $show->id('Id'); $show->name(trans('product/specification.name')); $show->attributes(trans('product/specification_attribute.index'),function (Grid $attributes){ $this->gridViewPermission($attributes); $attributes->setResource(route('admin.product.specification.attribute.index')); $attributes->id()->sortable(); $attributes->name(trans('product/specification_attribute.name'))->sortable(); $attributes->created_at(trans('admin.created_at'))->sortable(); $attributes->updated_at(trans('admin.updated_at'))->sortable(); }); $show->created_at(trans('admin.created_at')); $show->updated_at(trans('admin.updated_at')); return $show; } /** * Make a form builder. * * @return Form */ protected function form() { $form = new Form(new ProductSpecification); $this->formViewPermission($form); $form->text('name', trans('product/specification.name')) ->rules('unique:product_specifications') ->required(); $form->hasMany('attributes', trans('product/specification_attribute.index'), function (Form\NestedForm $form){ $form->text('name',trans('product/specification_attribute.name'))->required(); }); $form->saved(function (Form $form){ $form->model()->forgetCache(); }); return $form; } ... //laravel nova 表单、列表、详情 public function fields(Request $request) { $guardOptions = collect(config('auth.guards'))->mapWithKeys(function ($value, $key) { return [$key => __('nova-permission-tool::roles.guard_names.'.$key)]; }); $userResource = Nova::resourceForModel(getModelForGuard($this->guard_name)); return [ ID::make()->sortable(), Text::make(__('nova-permission-tool::roles.name'), 'name') ->rules(['required', 'string', 'max:255']) ->creationRules('unique:'.config('permission.table_names.roles')) ->updateRules('unique:'.config('permission.table_names.roles').',name,{{resourceId}}'), Text::make(__('nova-permission-tool::roles.guard_name'), function () { return __('nova-permission-tool::roles.guard_names.'.$this->guard_name); }), Select::make(__('nova-permission-tool::roles.guard_name'), 'guard_name') ->options($guardOptions->toArray()) ->rules(['required', Rule::in(array_keys($guardOptions->toArray()))]) ->onlyOnForms(), DateTime::make(__('nova-permission-tool::roles.created_at'), 'created_at')->exceptOnForms(), DateTime::make(__('nova-permission-tool::roles.updated_at'), 'updated_at')->exceptOnForms(), BelongsToMany::make(__('nova-permission-tool::resources.Permissions'), 'permissions', Permission::class)->searchable(), MorphToMany::make($userResource::label(), 'users', $userResource)->searchable(), ]; } 通过以上代码对比可以看出两个扩展在代码简洁性上有蛮大区别的。一个个字段写入翻译蛮麻烦的。在关系字段处理上需要关联表的控制器，然后增删改查又是一套... 当然这样也是有好处的，高度自定义，只不过一个后台管理用处不多，大多数可以自定义字段扩展出来。 laravel admin几乎把所有字段所需的 javaScript放在后端输出，其实这样对前端不友好，现在都前后端开始分离了，前端代码放在PHP中嵌套写蛮乱的，后期维护也相对困难。 结语 laravel nova和laravel admin都是非常好的扩展，只是国内大多数只知道拿人家的用，却很少去贡献，生态不如国外。两个扩展都朝着相同的目标，节省后台开发时间，但是一个收费，一个开源，而且laravel nova还是laravel作者团队开发的（框架加持）。扩展都是好扩展，要按项目需求和自己的熟练程度来选择使用哪种扩展开发后台，有能力两种都试试，深深体会一下。
前言 Google给我邮寄的PIN已经发出第三封了，我估计国内能妥投的概率非常低(都当废纸卖了)，等月底了上传资料验证身份好了。这几天一直在研究广告，包括广告收入和广告投放。之前没接触过广告这一块，不过多操作几次还是能得到不少经验的。 广告收入 网站有些访问量了，闲着没事干想着申请了Google Adsense投入广告。其实站点访问量并不大，但是好奇想着试试网站盈利是一种怎样的体验... Google Adsense的收入对于orzlee来说只是一个尝试，其中出现了很多简写单词： CPC - Cost PerClick 每次点击费用，即点击单价。 CPM - Cost Per Mile 千次展示费用，广告展示一千次需要支付的费用。 eCPM - Effective Cost Per Mille 千次展示收入。 RPM - Revenue Per Mille 千次展示收入(与eCPM同意，只是不同的广告联盟名称有所不同)。和CPM类似，RPM是针对广告展示商（比如Adsense商户）而言的。 CTR - Click-throughRate 点击率，点击次数占展示次数的百分比。 作为广告流量主来说这些最基本的还是要了解。Google Adsense目前自动广告虽然已经非常聪明了，但是还达不到完美，如果懒得折腾确实非常方便。很多样式并不是特别友好，甚至有些体验很糟糕。 orzlee就在一个以手机流量为主的站点使用过自动广告，经常展示广告会把整个网站向下顶，广告显示在网站顶部。说实话我都不想用了，其实是网站前端代码一塌糊涂，Google也无能为力。自动广告主要还是要靠前端布局规范(说实话我真的不喜欢折腾HTML，特别是css，这些才是真正的无聊)，那样自动广告就会非常融洽，怎么也不会那么突兀。 最近也试了一下Google Adsense广告单元，只是可以稍微自定样式，这样出来的广告就比较完美了。而且Google Adsense的广告很聪明，移动端会自适应布局，不会乱七八糟。 Google Adsense几乎是所有广告联盟中收益最高的了，但是也非常严格。orzlee也试过其他的广告商，如popcash、exoclick这些，说真的一天收入不如Google Adsense几次点击。貌似他们只算展示量，点击次数用来计算CTR，而CTR会提高你的eCPM。也就是说点击率高，你的千次展示收入就会越高，纯靠展示量获得收入，如果展示量很高但是点击率低，那你网站流量对该广告没有起到什么作用。归根结底就是展示广告目的就是引导用户广告发布商的网站（貌似现在没什么注册、安装的广告收入了，不过这类广告确实恶心），网站流量大，广告没人点，自然没什么收入。就连Google AdsenseRPM也是如此，一直在不停的波动，只不过Google Adsense计算点击收益，这个收益真的非常可观，我见过一次点击1.x美金，真是豪。 还忽略了一点，是我最喜欢也是最讨厌的，那就是AdBlock。这估计是所有站长的克星，现在用AdBlock的人真的非常多，这减少站长一笔收入，很烦。这东西真的没什么好的办法，Pornhub 使用WebSocket绕过广告屏蔽插件确实很犀利，但是对于一般的站长都是依赖广告联盟，想绕过广告联盟展示广告没什么资源。也有很多站长会提示自己的用户，要求对自己网站关掉AdBlock，甚至有些更加严格，网站都不让用户看。其实做站不容易，屏蔽掉哪些恶心的弹窗，入侵式广告就好了。 广告投放 广告投放只是小试牛刀，体验一下。我在popcash上投放的广告，最低0.5美金千次展示。 刚开始几乎没有怎么过滤流量，但是设置了单日最大金额，我设置的是1美金，创建一个Campaigns，一直在pending。等我过了两分钟再刷新立马1.3美金消费，我都设置单日最大限额1美金了，居然都拦不住，再去看站点流量真是猛，流量非常大，但是因为投放没有过滤，进来的流量几乎都是无效流量，短短几分钟就退回平常值了。我暂停了Campaigns，重新编辑过滤，限制非常严格，让流量更加精准有效。现在几乎一小时花0.01美金，流量不会瞬间上去了。 观察了几天流量小了很多，但是质量要高不少，最起码进来的流量停留时间要比开始长得多。毕竟不是做垃圾站，量多不如量精。首先我限制了流量语言，orzlee的站点并不是多语言站，先限制中文，国家也只选了几个中文用户较多的。还有一个就是流量来源，popcash做的不是很好，只有比较简单的来源筛选，其他的就看自己了。比如说浏览器、操作系统、设备。 其实广告投放还是谨慎点，多花点时间观测流量趋势，如果太多流量质量不好赶紧修改广告计划，不求流量大，只求流量精准。像个人站长广告投放可不能像大公司一样财大气粗，最重要的还是要自己站点质量，要留的住客户才行。 结语 什么事情都自己尝试一下，经验收获比看书看文章强多了。做网站运营广告是第一收入来源，当然不包括收费站点。终于知道站长有多恨AdBlock了，但这个是双向的，如果以前广告不那么恶心，也不至于逼得作者开发AdBlock，友好的广告也没人讨厌。中国垃圾站群真是多如牛毛，超恶心，搜索引擎一搜全是垃圾站。原创文章也越来越少了，写文章很花时间，多尊重作者吧。自己尝试了就明白他人的难处，总之多动手，学到的经验比现在赚到的钱价值高多了。现在学到的知识，以后会用金钱成倍的返还给你。
1. 为什么开始写博客 很久以前就发现同行很多人开始写博客了，归根结底就是自己太懒，不喜欢动手。 其实只要勤奋什么都可以做好，想想自己学习编程语言的那份激情，深更半夜还在敲代码，如今不也给我带来了收货吗。 2. 准备以哪主题为主 其实这个还有准备，想到什么就写什么吧，也没有硬性要求，这种感觉比上司安排工作限制时间轻松多了。真的渴望这种自由感。 博客也是一个知识累计的呈现，而orzlee又比较喜欢折腾各种新鲜有趣的东西，可能多数为这样的文章。 3. 说说自己吧 orzlee是一名PHPer，没有系统的学习过。接触过C,C++,JAVA。很多东西都是上网找资料（不过我学习之前就会翻墙了，google对于一名开发者真的是不可或缺的，至于百度真的不想多说什么）。在几年前还在写C#，而PHP已经崛起，接触的第一个框架就是laravel，然而过去几年了，还是用的laravel。 最近还抽风似的买了larvael nova,不过作者团队代码真的写的很好，刚出不久坑也很多，一路爬过来的。有时间可以去看看larvael nova介绍，Laracon 2018 - Taylor Otwell - Keynote（墙外），看Taylor Otwell敲代码真的很爽，sublimetext用的很溜。 结语 都说万事开头难，既然开头了，那就慢慢坚持吧（其实坚持更难）。