Skip to content

Commit fabaf66

Browse files
committed
feat: 自动清除小文件
1 parent 794631f commit fabaf66

File tree

10 files changed

+128
-24
lines changed

10 files changed

+128
-24
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Changelog
22

3-
## [0.0.10] - 2025-11-21
3+
## [0.0.10] - 2025-11-20
44

55
### 功能
66

77
- 新增支持推送渠道
8+
- 新增自动清除小文件
89
- 新增支持录制格式 mkv/ts
910
- 新增磁盘空间保护阈值选择
1011

internal/pkg/consts/system.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ const (
2424

2525
StorageThreshold = 90
2626

27-
SKFilenameTemplate = "sk_filename_template"
28-
SKArchiveStrategy = "sk_archive_strategy"
29-
SKLiveEndNotify = "sk_live_end_notify"
30-
SKDiskProtection = "sk_disk_protection"
27+
SKFilenameTemplate = "sk_filename_template"
28+
SKArchiveStrategy = "sk_archive_strategy"
29+
SKLiveEndNotify = "sk_live_end_notify"
30+
SKDiskProtection = "sk_disk_protection"
31+
SKAutoCleanLittleFile = "sk_auto_clean_little_file"
3132
)

internal/pkg/lives/lives_model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type LiveSession struct {
1313
Config LiveConfig
1414
State LiveState
1515
StartedAt *gtime.Time
16+
Filename string
1617
LiveApi LiveApi
1718
EventDispatcher interfaces.Module
1819
ListenerManager interfaces.Module

internal/pkg/recorders/event_biz.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package recorders
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
69

710
"github.com/gogf/gf/v2/frame/g"
811
"github.com/gogf/gf/v2/os/gctx"
@@ -31,6 +34,10 @@ func liveEndBiz(ctx context.Context, session *lives.LiveSession) {
3134
if enable == 1 {
3235
go message_push.LivePush(gctx.GetInitCtx(), session.State.Anchor, false)
3336
}
37+
autoClean := mr.GetSettingsManager().GetSetting(consts.SKAutoCleanLittleFile)
38+
if autoClean > 0 {
39+
go cleanLittleFiles(session.Filename, autoClean)
40+
}
3441
}
3542

3643
func addHistory(ctx context.Context, liveId int, anchor string, startTime, endTime *gtime.Time) {
@@ -57,3 +64,72 @@ func (*manager) updateName(ctx context.Context, session *lives.LiveSession) {
5764
}
5865
service.UpdateRoomInfo(ctx, session)
5966
}
67+
68+
func cleanLittleFiles(filename string, fileSize int) {
69+
if strings.TrimSpace(filename) == "" || fileSize <= 0 {
70+
return
71+
}
72+
73+
ctx := gctx.GetInitCtx()
74+
thresholdBytes := int64(fileSize) * 1024 * 1024
75+
76+
dir, name := filepath.Split(filename)
77+
ext := filepath.Ext(name)
78+
base := strings.TrimSuffix(name, ext)
79+
80+
origPath := filepath.Join(dir, name)
81+
82+
getFileSize := func(path string) (int64, bool) {
83+
info, err := os.Stat(path)
84+
if err != nil {
85+
if os.IsNotExist(err) {
86+
return 0, false
87+
}
88+
return 0, false
89+
}
90+
if !info.Mode().IsRegular() {
91+
return 0, false
92+
}
93+
return info.Size(), true
94+
}
95+
96+
deleteIfSmall := func(path string, threshold int64) bool {
97+
sz, ok := getFileSize(path)
98+
if !ok {
99+
return false
100+
}
101+
if sz < threshold {
102+
if err := os.Remove(path); err != nil {
103+
g.Log().Infof(ctx, "remove failed: %s, err: %v\n", path, err)
104+
return false
105+
}
106+
g.Log().Infof(ctx, "removed small file: %s (size=%d bytes, threshold=%d)\n", path, sz, threshold)
107+
return true
108+
}
109+
return false
110+
}
111+
112+
if _, exists := getFileSize(origPath); exists {
113+
_ = deleteIfSmall(origPath, thresholdBytes)
114+
return
115+
}
116+
117+
const maxParts = 1000
118+
deletedAny := false
119+
120+
for i := range maxParts {
121+
partName := fmt.Sprintf("%s_%03d%s", base, i, ext)
122+
partPath := filepath.Join(dir, partName)
123+
124+
if _, ok := getFileSize(partPath); !ok {
125+
break
126+
}
127+
128+
deleteIfSmall(partPath, thresholdBytes)
129+
}
130+
131+
if !deletedAny {
132+
g.Log().Info(ctx, "no little files found!")
133+
return
134+
}
135+
}

internal/pkg/recorders/live_recorder.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,8 @@ func (r *recorder) tryRecord(ctx context.Context) error {
136136
}
137137
r.setAndCloseParser(p)
138138
r.startTime = time.Now()
139-
err = r.parser.ParseLiveStream(ctx, streamInfo, fileName)
140-
removeEmptyFile(fileName)
141-
return err
139+
r.session.Filename = fileName
140+
return r.parser.ParseLiveStream(ctx, streamInfo, fileName)
142141
}
143142

144143
func (r *recorder) getQuality(streamInfos []*lives.StreamUrlInfo) *lives.StreamUrlInfo {
@@ -204,12 +203,6 @@ func newParser(cfg map[string]string) (parser.Parser, error) {
204203
return parser.New(ffmpeg_parser.Name, cfg)
205204
}
206205

207-
func removeEmptyFile(file string) {
208-
if stat, err := os.Stat(file); err == nil && stat.Size() == 0 {
209-
os.Remove(file)
210-
}
211-
}
212-
213206
func (r *recorder) run(ctx context.Context) {
214207
const maxBackoff = 5 * time.Minute
215208
backoff := 5 * time.Second

web/src/components/modal/stream/BatchAddRoomModal.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
</SelectTrigger>
4343
</FormControl>
4444
<SelectContent class="w-[--radix-select-trigger-width]">
45-
<SelectItem value="mkv">MKV</SelectItem>
4645
<SelectItem value="flv">FLV</SelectItem>
46+
<SelectItem value="mkv">MKV</SelectItem>
4747
<SelectItem value="ts">TS</SelectItem>
4848
<SelectItem value="mp4">MP4</SelectItem>
4949
<SelectItem value="mp3">MP3(仅音频)</SelectItem>
@@ -133,7 +133,7 @@ const { handleSubmit, resetForm } = useForm({
133133
initialValues: {
134134
roomUrls: "",
135135
interval: 30,
136-
format: "mkv",
136+
format: "flv",
137137
remark: "",
138138
},
139139
});

web/src/components/modal/stream/RoomModal.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
</SelectTrigger>
4040
</FormControl>
4141
<SelectContent class="w-[--radix-select-trigger-width]">
42-
<SelectItem value="mkv">MKV</SelectItem>
4342
<SelectItem value="flv">FLV</SelectItem>
43+
<SelectItem value="mkv">MKV</SelectItem>
4444
<SelectItem value="ts">TS</SelectItem>
4545
<SelectItem value="mp4">MP4</SelectItem>
4646
<SelectItem value="mp3">MP3(仅音频)</SelectItem>
@@ -276,7 +276,7 @@ const { handleSubmit, values, setValues, resetForm } = useForm({
276276
initialValues: {
277277
roomUrl: '',
278278
interval: 30,
279-
format: 'mkv',
279+
format: 'flv',
280280
monitorType: 0,
281281
quality: 0,
282282
segmentTime: 0,

web/src/lib/others/feature.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
{
22
"version": "0.0.10",
3-
"date": "2025-11-21",
3+
"date": "2025-11-20",
44
"info": {
55
"feature": {
66
"name": "功能",
77
"items": [
88
{
99
"desc": "新增支持推送渠道"
1010
},
11+
{
12+
"desc": "新增自动清除小文件"
13+
},
1114
{
1215
"desc": "新增支持录制格式 mkv/ts"
1316
},

web/src/views/index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<h1 class="text-xl font-semibold">Gowlive</h1>
99
</div>
1010
</SidebarHeader>
11-
<SidebarContent class="flex-grow p-2">
11+
<SidebarContent class="grow p-2">
1212
<SidebarMenu>
1313
<!-- 固定的主页菜单项 -->
1414
<SidebarMenuItem>
@@ -38,7 +38,7 @@
3838

3939
<div class="flex flex-1 flex-col">
4040
<Topbar />
41-
<main class="flex-grow p-4">
41+
<main class="grow p-4">
4242
<div class="h-full rounded-lg p-4">
4343
<router-view />
4444
</div>

web/src/views/users/LiveSettings.vue

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
</SelectContent>
4848
</Select>
4949
</div>
50+
</div>
51+
</CardContent>
52+
</Card>
53+
<Card>
54+
<CardContent>
55+
<div class="grid gap-2">
5056
<div class="flex items-center justify-between">
5157
<div class="flex items-center gap-1">
5258
<Label for="disk-protection" class="flex flex-col space-y-1">
@@ -70,16 +76,37 @@
7076
</SelectTrigger>
7177
<SelectContent>
7278
<SelectGroup>
73-
<SelectItem :value=0></SelectItem>
79+
<SelectItem :value=0>禁用</SelectItem>
7480
<SelectItem :value=5>5GB</SelectItem>
7581
<SelectItem :value=10>10GB</SelectItem>
7682
<SelectItem :value=20>20GB</SelectItem>
77-
<SelectItem :value=30>30GB</SelectItem>
7883
<SelectItem :value=50>50GB</SelectItem>
7984
</SelectGroup>
8085
</SelectContent>
8186
</Select>
8287
</div>
88+
<div class="flex items-center justify-between">
89+
<div class="flex items-center gap-1">
90+
<Label for="auto-clean-little-file" class="flex flex-col space-y-1">
91+
<span class="text-md">自动清除小文件</span>
92+
</Label>
93+
</div>
94+
<Select id="auto-clean-little-file" v-model="autoCleanLittleFile"
95+
@update:model-value="updateSetting('sk_auto_clean_little_file', $event)">
96+
<SelectTrigger class="w-[330px]">
97+
<SelectValue placeholder="选择小文件阈值" />
98+
</SelectTrigger>
99+
<SelectContent>
100+
<SelectGroup>
101+
<SelectItem :value=0>禁用</SelectItem>
102+
<SelectItem :value=20>20MB</SelectItem>
103+
<SelectItem :value=50>50MB</SelectItem>
104+
<SelectItem :value=100>100MB</SelectItem>
105+
<SelectItem :value=200>200MB</SelectItem>
106+
</SelectGroup>
107+
</SelectContent>
108+
</Select>
109+
</div>
83110
</div>
84111
</CardContent>
85112
</Card>
@@ -129,6 +156,7 @@ const liveEndNotify = ref(false);
129156
const filenameTemplate = ref<number>();
130157
const archiveStrategy = ref<number>();
131158
const diskProtection = ref<number>();
159+
const autoCleanLittleFile = ref<number>();
132160
133161
async function fetchSetting(key: string): Promise<Record<string, number>> {
134162
const res: any = await getSettings({ key });
@@ -140,11 +168,12 @@ async function fetchSetting(key: string): Promise<Record<string, number>> {
140168
let loadingSettings = true
141169
onMounted(async () => {
142170
try {
143-
const result: Record<string, number> = await fetchSetting('sk_live_end_notify,sk_filename_template,sk_archive_strategy,sk_disk_protection');
171+
const result: Record<string, number> = await fetchSetting('sk_live_end_notify,sk_filename_template,sk_archive_strategy,sk_disk_protection,sk_auto_clean_little_file');
144172
liveEndNotify.value = result['sk_live_end_notify'] == 1;
145173
filenameTemplate.value = result['sk_filename_template'] || 0;
146174
archiveStrategy.value = result['sk_archive_strategy'] || 0;
147175
diskProtection.value = result['sk_disk_protection'] || 0;
176+
autoCleanLittleFile.value = result['sk_auto_clean_little_file'] || 0;
148177
149178
bindToggleSetting(liveEndNotify, 'sk_live_end_notify');
150179
loadingSettings = false

0 commit comments

Comments
 (0)