2022新年快乐
2022新年快乐
2022新年快乐
*其实我已经有MBP,用了3年了。家里的NUC8是win11系统,想着平时在两个系统之间切换使用有点割裂感。就想把它装一个黑苹果。然后我在远景论坛搜到了一个大佬的帖子[OpenCore] NUC8最新OC EFI 持续更新(已更新至0.7.5+12.0.1)他分享出他的EFI文件,这样我就不需要去重新找驱动了,直接抄作业!其实,我大学时候就装过黑苹果,当时是四叶草引导,现在出现一个更优秀的引导OpenCore,我也顺便了解一下。后来在b站发现国光大佬的黑苹果教程视频版文字版,强烈建议大家全部看完。下面我说一下我的NUC8装黑苹果具体流程吧 我的NUC8没有硬改,此教程只适合没有硬改的NUC8 制作启动盘 准备一个16GB及以上的U盘,下载balenaEthcher镜像写入工具和macOS系统镜像。镜像可以去黑果小兵前辈下载最新的(需要关注公众号并赞赏),我把我下载的macOS12.0.1镜像分享出来 「macOS Monterey 12.0.1 21...141 and WEPE.dmg.pdf」,点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载,极速在线查看享用。(下载成功后记得把.pdf后缀删除) 链接:https://www.aliyundrive.com/s/HnADg1sgrDx 镜像和工具都下载好后,打开写入工具选择镜像选择u盘,点击flash即可 EFI归位 首先下载远景大佬的EFI文件,也可以从我这里下链接: https://pan.baidu.com/s/1SewgJJrvRT8U3sOnAjdglA 提取码: dz2k 。重新插拔第一步制作好的u盘,打开DiskGenius选择u盘并打开efi分区,删除此分区下所有内容。把下载好的efi文件解压后的efi文件夹复制进去。此时黑苹果启动u盘就算制作完成了 设置bios bios设置我直接复制远景大佬的推荐配置了。具体开机时按f2进去bios设置 详细设置如下: 按 F2 进入 BIOS,然后可以先重置 BIOS为出厂 默认设置。 Boot->Secure Boot-> “Secure Boot ” :取消勾选 Security->Security Features-> “Inter VT for directed I/VO (VT-d) ” : 取消勾选 Boot->Boot Priority->Legacy Boot Priority-> “ Legacy Boot ” :取消勾选 Boot->Boot Configuration->UEFI Boot->“ Fast Boot ”: 取消勾选 UEFI Boot->“ Boot USB Devices First ” : 勾选 UEFI Boot->“ Boot Network Devices Last ” :勾选 Boot Devices->“Network Boot” :Disable Power->Secondary Power Settings-> “ Wake on LAN from S4/S5 ” : Stay Off 开始装机 插入u盘,开机按f10进入boot menu,选择u盘(会出现两个u盘选项,一般选择第一个即可)。进入OpenCore界面,选择install xxxx。 ...
Aria2是一个非常成熟的下载程序,基于命令行调用。它也提供上RPC、WebSocket的调用方式。下面我会通过前端WebSocket调用的方式实现一个简单的下载功能 首先下载对应的Aria2可执行文件,并且命令行启动。aria2c默认会监听本地6800端口 aria2c --enable-rpc --rpc-listen-all=true --rpc-allow-origin-all 前端建立WebSocket连接,地址是:ws://localhost:6800/jsonrpc,具体代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>aria2</title> </head> <body> <div style="margin-bottom: 32px;"> <input type="text" id="ipt"> 下载进度:<span id="progress"></span> 下载速度:<span id="speed"></span> </div> <button id="start">开始下载</button> <button id="pause">暂停下载</button> <button id="unpause">恢复下载</button> <script> // Create WebSocket connection. const socket = new WebSocket('ws://localhost:6800/jsonrpc'); // Connection opened socket.addEventListener('open', function (event) { socket.send('Hello Server!'); console.log(event) }); let timer = {} let gid = '' // Listen for messages socket.addEventListener('message', function (event) { const data = JSON.parse(event.data) console.log('Message from server ', event.data) if (data.id === 'tellStatus') { const progress = parseInt(Number(data.result.completedLength) / Number(data.result.totalLength) * 100) + '%' const speed = parseInt(Number(data.result.downloadSpeed) / 1000) + ' kb/s' document.querySelector('#progress').innerHTML = progress document.querySelector('#speed').innerHTML = speed } if (data.method === 'aria2.onDownloadStart') { gid = data.params[0].gid const jsonData = { 'jsonrpc':'2.0', 'id':'tellStatus', 'method':'aria2.tellStatus', 'params': [gid] } if (!timer[gid]) { timer[gid] = setInterval(() => { socket.send(JSON.stringify(jsonData)) console.log('发送 tellStatus') }, 1000) } } if (data.method === 'aria2.onDownloadComplete') { gid = data.params[0].gid clearInterval(timer[gid]) delete timer[gid] document.querySelector('#progress').innerHTML = '100%' document.querySelector('#speed').innerHTML = '0 kb/s' } }); const startBtn = document.querySelector('#start') startBtn.addEventListener('click', function () { const jsonData = { 'jsonrpc':'2.0', 'id':'qwer', 'method':'aria2.addUri', 'params': [[ document.querySelector('#ipt').value ]] } socket.send(JSON.stringify(jsonData)) }) const pauseBtn = document.querySelector('#pause') const unpauseBtn = document.querySelector('#unpause') pauseBtn.addEventListener('click', function () { const jsonData = { 'jsonrpc':'2.0', 'id':'qwer', 'method':'aria2.pause', 'params': [gid] } socket.send(JSON.stringify(jsonData)) }) unpauseBtn.addEventListener('click', function () { const jsonData = { 'jsonrpc':'2.0', 'id':'qwer', 'method':'aria2.unpause', 'params': [gid] } socket.send(JSON.stringify(jsonData)) }) </script> </body> </html> Aria2官方文档:https://aria2.github.io/manual/en/html/index.html
本文使用node.js和ffmpeg实现了rtsp/rtmp直播流转m3u8 核心代码 const ffmpegPath = require('@ffmpeg-installer/ffmpeg') const ffmpeg = require('fluent-ffmpeg') const fs = require('fs') const path = require('path') const http = require('http') ffmpeg.setFfmpegPath(ffmpegPath.path) main() function main () { const rtsp = 'rtmp://192.168.31.249:1935/live/test' const m3u8 = './m3u8/live.m3u8' transcoding(rtsp, m3u8) createServer(7777) } function transcoding (rtsp, m3u8) { ffmpeg(rtsp) .outputOptions([ '-fflags flush_packets', '-max_delay 1', '-an', '-flags', '-global_header', '-hls_time 1', '-hls_list_size 3', '-hls_wrap 3', '-vcodec copy' ]) .on('start', function(e) { console.log('---开始转码---') console.log(e); }) .on('end', function() { console.log('file has been converted succesfully'); }) .on('error', function(err) { console.log('an error happened: ' + err.message); fun('error') }) .save(m3u8) } function createServer (port) { const mimes = { 'ts': 'video/MP2T', 'm3u8': 'application/x-mpegURL' } const liveServer = http.createServer((request, response) => { const urlArrs = request.url.split('.') const extension = urlArrs[urlArrs.length - 1] if (extension === 'ts') { try { response.setHeader('Content-Type', mimes['ts']) fs.createReadStream(path.join('./m3u8', request.url)).pipe(response) } catch (error) { response.end('hello world') } } else if (extension === 'm3u8') { try { response.setHeader('Content-Type', mimes['m3u8']) fs.createReadStream(path.join('./m3u8', request.url)).setEncoding('utf8').pipe(response) } catch (error) { response.end('hello world') } } else if (extension === 'html') { try { fs.createReadStream(path.join('./', request.url)).setEncoding('utf8').pipe(response) } catch (error) { response.end('hello world') } } else { response.end('hello world') } }) liveServer.listen(port, err => { console.log(err) console.log(`liveServer run ${port}`) }) } fluent-ffmpeg是ffmpeg的nodejs实现。你也可以使用child_process直接调用ffmpeg命令,原理是一样的。 @ffmpeg-installer/ffmpeg是一个ffmpeg安装器,可以根据当前系统安装对应的可执行文件。这里指定了ffmpeg的路径使用项目中下载好的。如果不指定会使用系统安装好的ffmpeg fluent-ffmpeg会把参数转化为ffmpeg命令,ffmpeg -i rtmp://192.168.31.249:1935/live/test -y -fflags flush_packets -max_delay 1 -an -flags -global_header -hls_time 1 -hls_list_size 3 -hls_wrap 3 -vcodec copy ./m3u8/live.m3u8 demo源码:https://github.com/blogwy/personal-practice/tree/master/rtsp-to-m3u8
什么是Strapi Strapi 是领先的开源Headless CMS。它是 100% JavaScript,完全可定制,有完善的开发文档,有现代化的管理面板且所以基础功能可视化操作,社区活跃。 Strapi特点 安装 环境要求 Node.js 12.x及以上 npm 6.x及以上 数据库支持 Database Minimum version SQLite 3 PostgreSQL 10 MySQL 5.6 MariaDB 10.1 MongoDB 3.6 Strapi v4, MongoDB不支持 创建项目 终端输入以下命令 npx create-strapi-app my-project or yarn create strapi-app my-project 选择安装类型 Quickstart(默认SQLite数据库) Custom(自定义数据库) 选择模版,选择y会出现官方的数据模版 输入项目名称 运行yarn develop运行项目(develop有热更新) 使用 注册并登录 第一次运行Strapi项目时候,会要求你注册一个账号,其实就是给当前系统添加一个超级管理员账号,注册好以后登录 创建集合(表) 点击侧边菜单内容类型生成器,点击创建新的Content Type,填入名称 点击继续,为当前集合创建字段,字段可以选择基本属性,比如是否唯一,必填等 为集合添加数据 点击侧边菜单集合名称,点击add 输入数据,点击save和publish ...
我们要写一个叫hello-cli的脚手架工具,它要做的是从GitHub拉去项目模版代码,把项目信息填入模版内即可。这是一个简单但是很常见的脚手架功能。脚手架源码 准备 开发脚手架工具,我们需要用到几个工具库 commander.js nodejs命令行完整解决方案,提供解析命令等功能,写脚手架必备库 inquirer.js 命令行交互工具,支持大部分形式。写脚手架必备库 download-git-repo 下载GitHub库 metalsmith 用于处理下载好的模版文件 handlebars 用户替换变量 ora.js 命令行loading样式,非必须 chalk.js 命令行文本加颜色背景等样式,非必须 log-symbols.js 给console.log添加有颜色的级别,例如error success,非必须 alphabetjs 字符文字样式,主要用于项目名称,非必须 开发 初始化项目,在package.json里面写入bin字段。key定义cli的命令hello-cli,value定义了命令的入口文件。 "bin": { "hello-cli": "bin/hello.js" } 入口文件hello.js 首先要在所有的命令入口文件前写#!/usr/bin/env node声明使用当前系统的node环境。这里会使用alphabetjs把项目名字输出一个字符文字,然后再定义一下usage description version脚手架的基础信息。command方法定义一个命令,命令的接收后处理需要写到一个名为 入口名-命令名.js 文件里面,这里我们需要在bin下面创建一个hello-create.js文件 #!/usr/bin/env node const commander = require('commander') const alphabetjs = require('alphabetjs') const chalk = require('chalk') const title = alphabetjs('Hello Cli','stereo') const packageInfo = require('../package.json') commander.addHelpText('beforeAll', chalk.greenBright(title)); commander .usage("[options]/[command]") .description('Hello World') .version(packageInfo.version) .command('create', 'Create an project') .parse(process.argv); create命令入口文件hello-create.js 使用commander.parse()方法解析输入的参数作为项目名,download方法下载模版,generator方法用来生成模版 ...
更新内容 v3.1.0 2021-06-29 新增扫码登录获取cookie,不需要手动设置 新增下载字幕功能
我的PS5国行到了,直观感觉“好大”!
项目地址:https://gitee.com/norman-ghost/website-template 预览地址:https://norman-ghost.gitee.io/website-template
美国NASA最近开放了2026年的“把你的名字送去火星”的计划,其实这个火星船票早在去年之前就有了,只不过今年莫名其妙就上了热搜。 申请地址:https://mars.nasa.gov/participate/send-your-name/future