设为首页收藏本站

 找回密码
 立即注册

只需一步,快速开始

搜索
查看: 98|回复: 16

[实用软件] PotPlayer 跳片头片尾小工具 | 支持 F7/F8/F9 | 文件名匹配 + 片头时间持久

 火.. [复制链接]
累计签到:22 天
连续签到:1 天
灌水成绩
8
54
4142
主题
帖子
积分

等级头衔

ID : 609

助理工程师

积分成就 测量币 : 4142
在线时间 : 0 小时
注册时间 : 2025-9-28
最后登录 : 2026-7-4

勋章
UID勋章测量学徒测量员
发表于 2026-4-16 19:02:45 | 显示全部楼层 |阅读模式 IP:北京
正文
大家好,分享一个自己写的 PotPlayer 小工具,主要用来快速跳过片头片尾,适合平时追番、追剧时使用。

这个工具最初是为了省掉每次手动拖动进度条的操作,现在整理成了单独的 exe,发出来给有同样需求的朋友试用。

功能说明

仅在 PotPlayer 窗口中生效,不会影响其他软件。
F7 跳转到当前视频对应的片头结束位置。
F8 跳转到当前视频对应的片尾开始位置。
F9 可记录当前播放位置为该文件名对应的片头时间,并自动持久化保存。
下次播放同系列文件时,F7 会优先使用已保存的片头时间。
源码
[Plain Text] 纯文本查看 复制代码; ================= 用户自定义区域:剧集时间配置 =================; 将你的剧集名称和对应时间按以下格式添加(一个剧集一行); 剧集名称可以灵活匹配,只要文件名中包含此关键词即可,如&quot;S01&quot;或&quot;Part.1&quot;TVSeriesConfig := &quot;(沧元图|90|1200凡人修仙传|85|1180斗破苍穹|95|1220)&quot;; 格式说明:每行是 &quot;剧集名称关键词|片头结束时间(秒)|片尾开始时间(秒)&quot;; ================= 用户自定义区域结束 =================PersistentIntroConfig := A_ScriptDir . &quot;\PotPlayer跳片头尾-通过文件名截取方式跳过.ini&quot;; 核心函数:根据当前播放文件匹配配置并跳转JumpBasedOnSeries(isIntro) {    seriesKey := GetCurrentSeriesKey()    if (seriesKey = &quot;&quot;) {        MsgBox, 未能识别当前播放文件名。        return    }    matchResult := FindSeriesTime(seriesKey, isIntro)    if !matchResult.found    {        if (isIntro = 1) {            MsgBox, 未找到当前播放文件的片头跳过配置。`n文件名关键词:%seriesKey%        } else {            MsgBox, 未找到当前播放文件的片尾跳过配置。`n文件名关键词:%seriesKey%        }        return    }    if (isIntro = 1) {        action := &quot;片头&quot;    } else {        action := &quot;片尾&quot;    }    JumpToTime(matchResult.time)    tipText := &quot;跳过来自 [&quot; . matchResult.seriesKey . &quot;] 的&quot; . action    ToolTip, %tipText%    SetTimer, RemoveToolTip, -2000}; 保存当前文件名对应的片头开始时间SaveCurrentIntroTime() {    Global PersistentIntroConfig    seriesKey := GetCurrentSeriesKey()    if (seriesKey = &quot;&quot;) {        MsgBox, 未能识别当前播放文件名,无法保存片头时间。        return    }    currentSeconds := GetCurrentPlaybackTime()    if (currentSeconds = &quot;&quot;) {        MsgBox, 未能获取当前播放时间,无法保存片头时间。        return    }    IniWrite, %currentSeconds%, %PersistentIntroConfig%, IntroTimes, %seriesKey%    formattedTime := FormatTime(currentSeconds)    ToolTip, 已保存 [%seriesKey%] 的片头时间:%formattedTime%    SetTimer, RemoveToolTip, -2000}; 查找当前文件对应的时间配置FindSeriesTime(seriesKey, isIntro) {    Global TVSeriesConfig    savedIntroTime := ReadSavedIntroTime(seriesKey)    Loop, Parse, TVSeriesConfig, `n, `r    {        if (A_LoopField = &quot;&quot;)            continue        StringSplit, configPart, A_LoopField, |        configKey := Trim(configPart1)        introTime := Trim(configPart2)        outroTime := Trim(configPart3)        if InStr(seriesKey, configKey)        {            if (isIntro = 1) {                targetTime := (savedIntroTime != &quot;&quot; ? savedIntroTime : introTime)                if (targetTime = &quot;&quot;)                    return {found: 0, seriesKey: configKey}                return {found: 1, time: targetTime + 0, seriesKey: configKey}            }            if (outroTime = &quot;&quot;)                return {found: 0, seriesKey: configKey}            return {found: 1, time: outroTime + 0, seriesKey: configKey}        }    }    if (isIntro = 1 && savedIntroTime != &quot;&quot;)        return {found: 1, time: savedIntroTime + 0, seriesKey: seriesKey}    return {found: 0, seriesKey: seriesKey}}; 读取持久化保存的片头时间ReadSavedIntroTime(seriesKey) {    Global PersistentIntroConfig    IniRead, introTime, %PersistentIntroConfig%, IntroTimes, %seriesKey%, __NOT_FOUND__    if (introTime = &quot;__NOT_FOUND__&quot;)        return &quot;&quot;    return introTime}; 获取当前播放文件的匹配关键词GetCurrentSeriesKey() {    if !IsPotPlayerActive()        return &quot;&quot;    WinGetTitle, currentTitle, A    return ExtractFolderName(currentTitle)}; 辅助函数:从窗口标题中提取文件名关键词ExtractFolderName(fullTitle) {    fileStr := RegExReplace(fullTitle, &quot;\s+-\s+PotPlayer.*$&quot;)    fileStr := Trim(fileStr)    SplitPath, fileStr, , , , nameNoExt    nameNoExt := Trim(nameNoExt)    if (InStr(nameNoExt, &quot;-&quot;)) {        StringSplit, parts, nameNoExt, -        folderName := Trim(parts1)    } else {        folderName := nameNoExt    }    return folderName}; 获取当前播放时间(秒)GetCurrentPlaybackTime() {    if !IsPotPlayerActive()        return &quot;&quot;    if !OpenTimeJumpDialog(playerHwnd, dialogHwnd)        return &quot;&quot;    ControlGetText, currentTime, Edit1, ahk_id %dialogHwnd%    CloseTimeJumpDialog(dialogHwnd, playerHwnd)    return ParseTimeToSeconds(currentTime)}; 解析 PotPlayer 中的时间文本ParseTimeToSeconds(timeText) {    timeText := Trim(timeText)    if (timeText = &quot;&quot;)        return &quot;&quot;    timeText := RegExReplace(timeText, &quot;\s.*$&quot;)    parts := StrSplit(timeText, &quot;:&quot;)    partCount := parts.MaxIndex()    if (partCount = 2) {        minutes := parts[1] + 0        secondsText := RegExReplace(parts[2], &quot;[^\d].*$&quot;)        return minutes * 60 + (secondsText + 0)    }    if (partCount >= 3) {        hours := parts[1] + 0        minutes := parts[2] + 0        secondsText := RegExReplace(parts[3], &quot;[^\d].*$&quot;)        return hours * 3600 + minutes * 60 + (secondsText + 0)    }    return &quot;&quot;}; ================= 核心跳转函数 =================JumpToTime(targetTimeInSeconds) {    if !IsPotPlayerActive()    {        MsgBox, 请先激活PotPlayer窗口!        return    }    formattedTime := FormatTime(targetTimeInSeconds)    if !OpenTimeJumpDialog(playerHwnd, dialogHwnd)    {        MsgBox, 未能打开 PotPlayer 的时间跳转窗口。        return    }    ControlFocus, Edit1, ahk_id %dialogHwnd%    ControlSetText, Edit1, %formattedTime%, ahk_id %dialogHwnd%    ControlSend, Edit1, {Enter}, ahk_id %dialogHwnd%    Sleep, 100    CloseTimeJumpDialog(dialogHwnd, playerHwnd)}; ================= 辅助函数:时间格式化 =================FormatTime(seconds) {    if (seconds < 3600) {        minutes := seconds // 60        secs := Mod(seconds, 60)        return Format(&quot;{:02}:{:02}&quot;, minutes, secs)    } else {        hours := seconds // 3600        minutes := Mod(seconds // 60, 60)        secs := Mod(seconds, 60)        return Format(&quot;{:02}:{:02}:{:02}&quot;, hours, minutes, secs)    }}; 判断当前激活窗口是否为 PotPlayerIsPotPlayerActive() {    WinGet, processName, ProcessName, A    WinGetClass, windowClass, A    return (processName = &quot;PotPlayerMini64.exe&quot;        || processName = &quot;PotPlayerMini.exe&quot;        || windowClass = &quot;PotPlayer64&quot;        || windowClass = &quot;PotPlayer&quot;)}OpenTimeJumpDialog(ByRef playerHwnd, ByRef dialogHwnd) {    playerHwnd := WinExist(&quot;A&quot;)    Send, g    WinWaitActive, ahk_class #32770,, 1    if ErrorLevel        return 0    dialogHwnd := WinExist(&quot;A&quot;)    return dialogHwnd ? 1 : 0}CloseTimeJumpDialog(dialogHwnd, playerHwnd := 0) {    dialogWinTitle := &quot;ahk_id &quot; . dialogHwnd    playerWinTitle := &quot;ahk_id &quot; . playerHwnd    if (dialogHwnd && WinExist(dialogWinTitle)) {        WinActivate, %dialogWinTitle%        Sleep, 50        SendInput, !c        WinWaitClose, %dialogWinTitle%,, 1    }    if (playerHwnd && WinExist(playerWinTitle))        WinActivate, %playerWinTitle%}RemoveToolTip:    ToolTipreturn#If IsPotPlayerActive()F7::  ; 按下 F7,跳过来自匹配剧集的片头    JumpBasedOnSeries(1)returnF8::  ; 按下 F8,跳过来自匹配剧集的片尾    JumpBasedOnSeries(0)returnF9::  ; 按下 F9,保存当前文件名对应的片头起始时间    SaveCurrentIntroTime()return#If
工作方式
程序会根据当前播放文件名提取关键词进行匹配。
默认可在脚本配置中预设片头和片尾时间。
如果某一集的片头时间想手动微调,可以直接在对应位置按 F9 保存,后续会自动读取保存结果。

适用场景

同一动画、剧集的大部分集数片头片尾时间相近。
文件名有相对固定的命名规律。
希望用快捷键快速跳过,不想每次手动拖进度条。
使用方法

运行程序。
打开 PotPlayer 播放视频。
按 F7 跳片头,按 F8 跳片尾。
如果当前集片头位置需要重新记录,先把视频播放到目标位置,再按 F9 保存。
说明

工具仅针对 PotPlayer 使用。
配置文件会保存在程序目录下,方便后续直接读取。
exe 由 AutoHotkey 打包生成,部分安全软件可能会有误报,这类情况属于脚本类程序常见现象;介意的话可以直接查看源码版。
程序是自用后整理分享,欢迎反馈命名规则兼容性和使用问题。
更新内容

限制热键只在 PotPlayer 中生效。
新增 F9 记录片头时间并持久化。
修正跳转窗口关闭逻辑,避免误关闭视频。
下载方式
PotPlayer跳片头尾-通过文件名截取方式跳过.zip

演示截图

PotPlayer 播放界面截图

配置保存效果截图

INI 持久化截图

结尾
如果这个小工具对你有帮助,欢迎回复反馈。
如果后续有新的功能想法,比如自动识别更多命名格式、支持更多播放器,我也可以继续完善。
累计签到:59 天
连续签到:47 天
灌水成绩
2
223
14807
主题
帖子
积分

等级头衔

ID : 523

中级工程师

积分成就 测量币 : 14807
在线时间 : 521 小时
注册时间 : 2026-2-17
最后登录 : 2026-7-5

勋章
发表于 2026-4-19 22:18:51 | 显示全部楼层 IP:美国
内容不水,全是干货。
回复

使用道具 举报

累计签到:62 天
连续签到:45 天
灌水成绩
3
212
14135
主题
帖子
积分

等级头衔

ID : 563

中级工程师

积分成就 测量币 : 14135
在线时间 : 527 小时
注册时间 : 2025-11-11
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-4-30 02:09:19 | 显示全部楼层 IP:广东东莞
对提升编码效率很有帮助。
回复

使用道具 举报

累计签到:55 天
连续签到:48 天
灌水成绩
3
225
14962
主题
帖子
积分

等级头衔

ID : 575

中级工程师

积分成就 测量币 : 14962
在线时间 : 533 小时
注册时间 : 2026-3-24
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-4-30 12:30:01 | 显示全部楼层 IP:北京
代码可直接运行,省去很多调试时间。
回复

使用道具 举报

累计签到:61 天
连续签到:43 天
灌水成绩
5
204
13044
主题
帖子
积分

等级头衔

ID : 536

中级工程师

积分成就 测量币 : 13044
在线时间 : 525 小时
注册时间 : 2026-1-14
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-5-1 01:19:47 | 显示全部楼层 IP:广东东莞
学到了新思路,感谢。
回复

使用道具 举报

累计签到:33 天
连续签到:2 天
灌水成绩
2
216
15221
主题
帖子
积分

等级头衔

ID : 590

中级工程师

积分成就 测量币 : 15221
在线时间 : 0 小时
注册时间 : 2026-2-25
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-5-1 01:19:47 | 显示全部楼层 IP:广东东莞
知识点梳理得很清楚。
回复

使用道具 举报

累计签到:28 天
连续签到:1 天
灌水成绩
1
201
13490
主题
帖子
积分

等级头衔

ID : 599

中级工程师

积分成就 测量币 : 13490
在线时间 : 0 小时
注册时间 : 2025-12-25
最后登录 : 2026-7-4

勋章
UID勋章测量学徒测量员
发表于 2026-5-1 01:21:43 | 显示全部楼层 IP:广东东莞
看完这篇终于搞懂原理了。
回复

使用道具 举报

累计签到:56 天
连续签到:46 天
灌水成绩
4
230
14545
主题
帖子
积分

等级头衔

ID : 566

中级工程师

积分成就 测量币 : 14545
在线时间 : 529 小时
注册时间 : 2026-1-23
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-5-1 01:41:59 | 显示全部楼层 IP:广东东莞
对提升编码效率很有帮助。
回复

使用道具 举报

累计签到:52 天
连续签到:47 天
灌水成绩
3
236
15725
主题
帖子
积分

等级头衔

ID : 531

中级工程师

积分成就 测量币 : 15725
在线时间 : 523 小时
注册时间 : 2026-1-28
最后登录 : 2026-7-5

勋章
UID勋章测量学徒测量员
发表于 2026-5-1 01:43:51 | 显示全部楼层 IP:广东东莞
很多技巧平时工作中真的能用。
回复

使用道具 举报

累计签到:10 天
连续签到:1 天
灌水成绩
0
35
1661
主题
帖子
积分

等级头衔

ID : 2177

高级技术员

积分成就 测量币 : 1661
在线时间 : 0 小时
注册时间 : 2026-5-25
最后登录 : 2026-7-5

勋章
测量员
发表于 2026-5-27 00:26:19 | 显示全部楼层 IP:广东东莞
学习了,谢谢分享、、、
回复

使用道具 举报

快速回复换一批
感谢楼主,好人一生平安
顶顶顶
马克一下
先赞后看,养成习惯! 感谢大佬指路,回帖留名以备日后查阅。 📝🚀
自古二楼出人才? 我来占个前排,楼主继续,不要停! 🏃‍♂️💨
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|精密测量技术论坛 ( 桂ICP备2026007449号-1 )

GMT+8, 2026-7-5 13:59 , Processed in 1.030575 second(s), 52 queries .

Powered by 精密测量技术论坛

© 2025-2026 联系站长

快速回复 返回顶部 返回列表