mirror of
				https://github.com/langhuihui/monibuca.git
				synced 2025-10-31 16:16:19 +08:00 
			
		
		
		
	feat: crontab init sql
This commit is contained in:
		
							
								
								
									
										170
									
								
								plugin/crontab/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								plugin/crontab/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| # M7S Crontab 插件说明文档 | ||||
|  | ||||
| ## 1. 插件概述 | ||||
|  | ||||
| Crontab 插件是 M7S 流媒体服务器的一个扩展组件,主要用于实现基于时间计划的自动录制功能。该插件允许用户创建定时录制计划,根据预设的时间表自动开始和停止流媒体的录制,支持灵活的周期性录制设置。 | ||||
|  | ||||
| ## 2. 核心功能 | ||||
|  | ||||
| - **定时录制计划管理**:创建、更新、删除和查询录制计划 | ||||
| - **流路径关联**:将录制计划与特定的流路径关联 | ||||
| - **时间表设置**:通过 168 位的二进制字符串(7天×24小时)定义每周的录制时间段 | ||||
| - **自动录制控制**:根据时间计划自动开始和停止录制 | ||||
| - **状态监控**:查询当前正在执行和计划中的录制任务状态 | ||||
|  | ||||
| ## 3. 文件结构与功能 | ||||
|  | ||||
| ### 3.1 主要文件 | ||||
|  | ||||
| #### 3.1.1 `index.go` | ||||
|  | ||||
| 插件的入口文件,定义了 `CrontabPlugin` 结构体和初始化方法。 | ||||
|  | ||||
| - **主要结构**: | ||||
|   - `CrontabPlugin`:插件的主结构体,包含插件基础功能、API服务器实现和数据集合 | ||||
| - **主要功能**: | ||||
|   - `OnInit()`:插件初始化函数,负责数据库迁移、加载已有录制计划并创建相应的定时任务 | ||||
|  | ||||
| #### 3.1.2 `crontab.go` | ||||
|  | ||||
| 定义了定时任务的核心逻辑和执行流程。 | ||||
|  | ||||
| - **主要结构**: | ||||
|   - `TimeSlot`:表示一个时间段,包含开始和结束时间 | ||||
|   - `Crontab`:定时任务调度器,负责根据计划执行录制操作 | ||||
| - **主要功能**: | ||||
|   - `Start()`:初始化定时任务 | ||||
|   - `Run()`:阻塞运行定时任务,循环检查并执行录制操作 | ||||
|   - `Dispose()`:停止定时任务 | ||||
|   - `getNextTimeSlot()`:计算下一个需要执行的时间段 | ||||
|   - `startRecording()`:开始录制流 | ||||
|   - `stopRecording()`:停止录制流 | ||||
|  | ||||
| #### 3.1.3 `api.go` | ||||
|  | ||||
| 实现了插件的 API 接口,提供了与前端交互的功能。 | ||||
|  | ||||
| - **主要功能**: | ||||
|   - 录制计划管理:`List()`, `Add()`, `Update()`, `Remove()` | ||||
|   - 录制计划流关联管理:`ListRecordPlanStreams()`, `AddRecordPlanStream()`, `UpdateRecordPlanStream()`, `RemoveRecordPlanStream()` | ||||
|   - 计划解析:`ParsePlanTime()` | ||||
|   - 状态查询:`GetCrontabStatus()` | ||||
| - **辅助功能**: | ||||
|   - 时间计算:`getWeekdayName()`, `getWeekdayIndex()`, `getNextDateForWeekday()` | ||||
|   - 时间段计算:`calculateTimeSlots()`, `getNextTimeSlotFromNow()` | ||||
|  | ||||
| ### 3.2 子目录文件 | ||||
|  | ||||
| #### 3.2.1 `pkg` 目录 | ||||
|  | ||||
| 包含数据模型定义和数据库操作相关功能。 | ||||
|  | ||||
| - **`recordplan.go`**: | ||||
|   - 定义 `RecordPlan` 结构体,表示录制计划的数据模型 | ||||
|   - 包含计划ID、名称、时间表和启用状态等字段 | ||||
|  | ||||
| - **`recordplanstream.go`**: | ||||
|   - 定义 `RecordPlanStream` 结构体,表示录制计划与流路径的关联 | ||||
|   - 提供数据库查询的辅助函数,如按流路径模糊查询、按创建时间排序等 | ||||
|  | ||||
| #### 3.2.2 `pb` 目录 | ||||
|  | ||||
| 包含 Protocol Buffers 定义和生成的代码,用于 API 接口和数据传输。 | ||||
|  | ||||
| - **`crontab.proto`**: | ||||
|   - 定义了插件的 API 服务接口 | ||||
|   - 定义了各种请求和响应消息结构 | ||||
|   - 包含 HTTP 路由映射配置 | ||||
|  | ||||
| - **`crontab.pb.go`, `crontab.pb.gw.go`, `crontab_grpc.pb.go`**: | ||||
|   - 由 Protocol Buffers 编译器自动生成的 Go 代码 | ||||
|   - 实现了消息序列化/反序列化和 gRPC 服务接口 | ||||
|  | ||||
| ## 4. 工作流程 | ||||
|  | ||||
| ### 4.1 插件初始化流程 | ||||
|  | ||||
| 1. 插件启动时,`OnInit()` 方法被调用 | ||||
| 2. 执行数据库迁移,确保必要的表结构存在 | ||||
| 3. 从数据库加载所有录制计划和关联的流信息 | ||||
| 4. 对于已启用的计划,创建并启动相应的定时任务 | ||||
|  | ||||
| ### 4.2 录制计划执行流程 | ||||
|  | ||||
| 1. 定时任务启动后,进入 `Run()` 方法的循环 | ||||
| 2. 通过 `getNextTimeSlot()` 计算下一个需要执行的时间段 | ||||
| 3. 设置定时器等待到达开始时间 | ||||
| 4. 到达开始时间后,调用 `startRecording()` 开始录制 | ||||
| 5. 设置定时器等待到达结束时间 | ||||
| 6. 到达结束时间后,调用 `stopRecording()` 停止录制 | ||||
| 7. 循环继续,计算下一个时间段 | ||||
|  | ||||
| ### 4.3 API 交互流程 | ||||
|  | ||||
| 1. 前端通过 HTTP/gRPC 接口与插件交互 | ||||
| 2. 可以创建、更新、删除录制计划和流关联 | ||||
| 3. 可以查询当前正在执行和计划中的录制任务状态 | ||||
| 4. 可以解析计划字符串,获取时间段信息 | ||||
|  | ||||
| ## 5. 关键概念 | ||||
|  | ||||
| ### 5.1 录制计划 (RecordPlan) | ||||
|  | ||||
| 录制计划定义了何时进行录制的时间表。每个计划包含: | ||||
| - **ID**:唯一标识符 | ||||
| - **名称**:计划名称 | ||||
| - **时间表**:168位的二进制字符串,表示一周中每个小时是否进行录制 | ||||
| - **启用状态**:是否启用该计划 | ||||
|  | ||||
| ### 5.2 录制计划流 (RecordPlanStream) | ||||
|  | ||||
| 将录制计划与特定的流路径关联,定义了录制的具体参数: | ||||
| - **计划ID**:关联的录制计划ID | ||||
| - **流路径**:要录制的流的路径 | ||||
| - **分片设置**:录制文件的分片参数 | ||||
| - **文件路径**:录制文件的保存路径 | ||||
| - **启用状态**:是否启用该关联 | ||||
|  | ||||
| ### 5.3 时间表格式 | ||||
|  | ||||
| 时间表使用 168 位的二进制字符串表示一周中的每个小时是否进行录制: | ||||
| - 每天 24 小时,一周 7 天,共 168 小时 | ||||
| - 字符串中的每一位对应一个小时,'1' 表示录制,'0' 表示不录制 | ||||
| - 字符串按周日到周六的顺序排列,每天 24 位 | ||||
|  | ||||
| 例如: | ||||
| - 全为 '0':一周中不进行任何录制 | ||||
| - 前 24 位为 '1',其余为 '0':仅在周日全天录制 | ||||
| - 每天的第 9 位到第 17 位为 '1':每天上午 9 点到下午 5 点录制 | ||||
|  | ||||
| ## 6. 使用场景 | ||||
|  | ||||
| 1. **定期节目录制**:适用于每周固定时间播出的节目自动录制 | ||||
| 2. **工作时间监控**:仅在工作时间段自动录制监控视频 | ||||
| 3. **带宽管理**:在网络带宽充足的时间段进行录制,避开高峰期 | ||||
| 4. **存储优化**:只录制有价值的时间段,节省存储空间 | ||||
|  | ||||
| ## 7. API 接口说明 | ||||
|  | ||||
| ### 7.1 录制计划管理 | ||||
|  | ||||
| - **列表查询**:`GET /plan/api/list` | ||||
| - **添加计划**:`POST /plan/api/add` | ||||
| - **更新计划**:`POST /plan/api/update/{id}` | ||||
| - **删除计划**:`POST /plan/api/remove/{id}` | ||||
|  | ||||
| ### 7.2 录制计划流管理 | ||||
|  | ||||
| - **列表查询**:`GET /planstream/api/list` | ||||
| - **添加关联**:`POST /planstream/api/add` | ||||
| - **更新关联**:`POST /planstream/api/update` | ||||
| - **删除关联**:`POST /planstream/api/remove/{planId}/{streamPath}` | ||||
|  | ||||
| ### 7.3 其他接口 | ||||
|  | ||||
| - **解析计划**:`GET /plan/api/parse/{plan}` | ||||
| - **状态查询**:`GET /crontab/api/status` | ||||
|  | ||||
| ## 8. 总结 | ||||
|  | ||||
| Crontab 插件为 M7S 流媒体服务器提供了强大的定时录制功能,通过灵活的时间表设置和流路径关联,实现了自动化的录制控制。该插件适用于需要定期录制特定时间段流媒体内容的场景,能有效节省人力和存储资源。 | ||||
| @@ -32,6 +32,9 @@ func (ct *CrontabPlugin) OnInit() (err error) { | ||||
| 		} | ||||
| 		ct.Info("init database success") | ||||
|  | ||||
| 		// 初始化默认录制计划(工作日和周末计划) | ||||
| 		ct.InitDefaultPlans() | ||||
|  | ||||
| 		// 查询所有录制计划 | ||||
| 		var plans []pkg.RecordPlan | ||||
| 		if err = ct.DB.Find(&plans).Error; err != nil { | ||||
|   | ||||
							
								
								
									
										84
									
								
								plugin/crontab/init_data.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								plugin/crontab/init_data.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| package plugin_crontab | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"m7s.live/v5/plugin/crontab/pkg" | ||||
| ) | ||||
|  | ||||
| // InitDefaultPlans 初始化默认的录制计划 | ||||
| // 包括工作日录制计划和周末录制计划 | ||||
| func (ct *CrontabPlugin) InitDefaultPlans() { | ||||
| 	// 创建工作日录制计划(周一到周五全天录制)的计划字符串 | ||||
| 	workdayPlanStr := buildPlanString(false, true, true, true, true, true, false) // 周一到周五 | ||||
|  | ||||
| 	// 检查是否已存在相同内容的工作日录制计划 | ||||
| 	var count int64 | ||||
| 	if err := ct.DB.Model(&pkg.RecordPlan{}).Where("plan = ?", workdayPlanStr).Count(&count).Error; err != nil { | ||||
| 		ct.Error("检查工作日录制计划失败: %v", err) | ||||
| 	} else if count == 0 { | ||||
| 		// 不存在相同内容的计划,创建新计划 | ||||
| 		workdayPlan := &pkg.RecordPlan{ | ||||
| 			Name:   "工作日录制计划", | ||||
| 			Plan:   workdayPlanStr, | ||||
| 			Enable: true, | ||||
| 		} | ||||
|  | ||||
| 		if err := ct.DB.Create(workdayPlan).Error; err != nil { | ||||
| 			ct.Error("创建工作日录制计划失败: %v", err) | ||||
| 		} else { | ||||
| 			ct.Info("成功创建工作日录制计划") | ||||
| 			// 添加到内存中 | ||||
| 			ct.recordPlans.Add(workdayPlan) | ||||
| 		} | ||||
| 	} else { | ||||
| 		ct.Info("已存在相同内容的工作日录制计划,跳过创建") | ||||
| 	} | ||||
|  | ||||
| 	// 创建周末录制计划(周六和周日全天录制)的计划字符串 | ||||
| 	weekendPlanStr := buildPlanString(true, false, false, false, false, false, true) // 周日和周六 | ||||
|  | ||||
| 	// 检查是否已存在相同内容的周末录制计划 | ||||
| 	if err := ct.DB.Model(&pkg.RecordPlan{}).Where("plan = ?", weekendPlanStr).Count(&count).Error; err != nil { | ||||
| 		ct.Error("检查周末录制计划失败: %v", err) | ||||
| 	} else if count == 0 { | ||||
| 		// 不存在相同内容的计划,创建新计划 | ||||
| 		weekendPlan := &pkg.RecordPlan{ | ||||
| 			Name:   "周末录制计划", | ||||
| 			Plan:   weekendPlanStr, | ||||
| 			Enable: true, | ||||
| 		} | ||||
|  | ||||
| 		if err := ct.DB.Create(weekendPlan).Error; err != nil { | ||||
| 			ct.Error("创建周末录制计划失败: %v", err) | ||||
| 		} else { | ||||
| 			ct.Info("成功创建周末录制计划") | ||||
| 			// 添加到内存中 | ||||
| 			ct.recordPlans.Add(weekendPlan) | ||||
| 		} | ||||
| 	} else { | ||||
| 		ct.Info("已存在相同内容的周末录制计划,跳过创建") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // buildPlanString 构建计划字符串 | ||||
| // 参数分别表示:周日、周一、周二、周三、周四、周五、周六是否录制 | ||||
| // 返回168位的计划字符串,每天24小时,一周7天 | ||||
| func buildPlanString(sun, mon, tue, wed, thu, fri, sat bool) string { | ||||
| 	var planBuilder strings.Builder | ||||
|  | ||||
| 	// 按照周日、周一、...、周六的顺序 | ||||
| 	days := []bool{sun, mon, tue, wed, thu, fri, sat} | ||||
| 	 | ||||
| 	for _, record := range days { | ||||
| 		if record { | ||||
| 			// 该天录制,24小时都为1 | ||||
| 			planBuilder.WriteString(strings.Repeat("1", 24)) | ||||
| 		} else { | ||||
| 			// 该天不录制,24小时都为0 | ||||
| 			planBuilder.WriteString(strings.Repeat("0", 24)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return planBuilder.String() | ||||
| } | ||||
							
								
								
									
										60
									
								
								plugin/crontab/init_plans.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								plugin/crontab/init_plans.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| -- 初始化录制计划的 SQL 脚本 | ||||
| -- 包含两个预设计划:工作日全天录制和周末全天录制 | ||||
|  | ||||
| -- 工作日计划(周一到周五全天录制) | ||||
| INSERT INTO record_plans (name, plan, enable, created_at, updated_at) | ||||
| SELECT '工作日录制计划',  | ||||
|        -- 168位的计划字符串,格式为: | ||||
|        -- 前24位为周日,接着24位为周一,以此类推到周六 | ||||
|        -- 0表示不录制,1表示录制 | ||||
|        -- 工作日录制:周一到周五全为1,周六周日全为0 | ||||
|        CONCAT( | ||||
|          -- 周日(0):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周一(1):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周二(2):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周三(3):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周四(4):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周五(5):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周六(6):24个0 | ||||
|          REPEAT('0', 24) | ||||
|        ), | ||||
|        TRUE, -- 启用状态 | ||||
|        NOW(), -- 创建时间 | ||||
|        NOW()  -- 更新时间 | ||||
| WHERE NOT EXISTS ( | ||||
|     SELECT 1 FROM record_plans WHERE name = '工作日录制计划' | ||||
| ); | ||||
|  | ||||
| -- 周末计划(周六和周日全天录制) | ||||
| INSERT INTO record_plans (name, plan, enable, created_at, updated_at) | ||||
| SELECT '周末录制计划',  | ||||
|        -- 168位的计划字符串 | ||||
|        -- 周末录制:周六周日全为1,周一到周五全为0 | ||||
|        CONCAT( | ||||
|          -- 周日(0):24个1 | ||||
|          REPEAT('1', 24), | ||||
|          -- 周一(1):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周二(2):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周三(3):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周四(4):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周五(5):24个0 | ||||
|          REPEAT('0', 24), | ||||
|          -- 周六(6):24个1 | ||||
|          REPEAT('1', 24) | ||||
|        ), | ||||
|        TRUE, -- 启用状态 | ||||
|        NOW(), -- 创建时间 | ||||
|        NOW()  -- 更新时间 | ||||
| WHERE NOT EXISTS ( | ||||
|     SELECT 1 FROM record_plans WHERE name = '周末录制计划' | ||||
| ); | ||||
		Reference in New Issue
	
	Block a user
	 pggiroro
					pggiroro