还在看视频时切来切去记笔记?我用 Python 写了个带时间戳的播放器,效率提升 10 倍

56 阅读6分钟

痛点:学习视频时的笔记噩梦

你是不是也经历过这样的场景:

刷技术教程、看课程录像、学习编程视频时,需要频繁在视频播放器笔记软件之间切换:

  • 看到重点内容,暂停视频 → 切到笔记软件 → 记录要点 → 手动输入时间戳 → 切回视频继续看
  • 稍微一不留神,又得来回拖动进度条定位
  • 多个学习视频混在一起,笔记管理混乱,想回顾某个知识点找不到在哪

这种"切换-记录-再切换"的循环,不仅打断学习节奏,还容易遗漏关键信息。如果能在看视频的同时,直接在旁边记笔记,并且能一键跳转到视频对应位置,该多好?

于是我花了点时间,用 Python 写了一个视频播放器笔记应用,完美解决了这个问题。

test.gif

核心功能设计

这个应用主要解决了三个核心痛点:

1. 视频播放与笔记一体化

  • 左侧是视频播放区域,右侧是 Markdown 笔记编辑器
  • 支持常见视频格式(MP4、AVI、MKV、MOV 等)
  • 全键盘操作,双手不离键盘就能完成所有操作

2. 时间戳自动关联

  • Ctrl+T 一键插入当前视频时间戳
  • 点击笔记中的时间戳,视频自动跳转到对应位置
  • 笔记和视频位置双向绑定,回顾笔记时可以快速定位视频内容

3. 项目化管理

  • 每个视频自动创建独立项目
  • 笔记自动保存,无需手动操作
  • 支持 Markdown/HTML 导出,方便分享

技术实现方案

项目采用经典的三层架构,代码结构清晰易扩展:

video-player-notes/
├── gui/                 # 用户界面层(PyQt5)
├── services/            # 业务逻辑层
├── repositories/        # 数据持久层(SQLite)
├── models/              # 数据模型
└── main.py             # 应用入口

1. 视频播放:VLC + PyQt5

视频播放使用 python-vlc 作为后端,PyQt5 作为前端容器:

from PyQt5.QtWidgets import QWidget, QVBoxLayout
import vlc

class VideoWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.instance = vlc.Instance()
        self.player = self.instance.media_player_new()

        # 创建播放器容器
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)

    def load_video(self, file_path: str):
        media = self.instance.media_new(file_path)
        self.player.set_media(media)
        self.player.play()

关键技术点

  • VLC 提供强大的视频解码能力,支持几乎所有格式
  • PyQt5 的 QWidget 作为 VLC 播放器的父容器
  • 通过 set_hwnd() 方法将播放器嵌入到窗口中

2. 时间戳管理

时间戳是整个应用的核心,需要精确记录和快速跳转:

from dataclasses import dataclass
from typing import Optional

@dataclass
class Timestamp:
    id: int
    note_id: int
    position: float  # 视频位置(秒)
    display_time: str  # 格式化显示 (MM:SS)
    content: str  # 时间戳关联的内容

    @classmethod
    def from_position(cls, note_id: int, position: float) -> 'Timestamp':
        """从视频位置创建时间戳"""
        minutes = int(position // 60)
        seconds = int(position % 60)
        display_time = f"{minutes:02d}:{seconds:02d}"
        return cls(
            id=0,
            note_id=note_id,
            position=position,
            display_time=display_time,
            content=""
        )

# 在笔记编辑器中插入时间戳
def insert_timestamp(self):
    current_time = self.video_service.get_current_position()
    timestamp = Timestamp.from_position(
        note_id=self.current_note.id,
        position=current_time
    )

    # 插入 Markdown 格式的时间戳链接
    timestamp_link = f"[{timestamp.display_time}](#t{timestamp.position})"
    self.note_editor.insert_text(timestamp_link)

    # 保存到数据库
    self.timestamp_service.save_timestamp(timestamp)

亮点设计

  • 时间戳存储为 Markdown 链接格式 [MM:SS](#t123.45)
  • 点击链接时解析时间值,调用 player.set_time() 跳转
  • 数据库持久化所有时间戳,支持搜索和统计

3. 笔记编辑器:Markdown 实时预览

使用 python-markdownPygments 实现即时预览:

import markdown
from PyQt5.QtWebEngineWidgets import QWebEngineView

class NoteEditor(QWidget):
    def __init__(self):
        super().__init__()
        self.text_input = QTextEdit()
        self.preview = QWebEngineView()

        # 实时预览更新
        self.text_input.textChanged.connect(self.update_preview)

    def update_preview(self):
        raw_text = self.text_input.toPlainText()

        # Markdown 转 HTML
        md = markdown.Markdown(
            extensions=['fenced_code', 'tables', 'codehilite']
        )
        html_content = md.convert(raw_text)

        # 添加自定义样式
        styled_html = f"""
        <html>
        <head>
            <style>
                body {{ font-family: 'Microsoft YaHei', sans-serif; }}
                code {{ background: #f4f4f4; padding: 2px 6px; }}
                pre {{ background: #2d2d2d; color: #f8f8f2; }}
            </style>
        </head>
        <body>{html_content}</body>
        </html>
        """
        self.preview.setHtml(styled_html)

4. 数据持久化:SQLite

使用 SQLite 存储笔记和项目数据,轻量且无需额外配置:

import sqlite3
from contextlib import contextmanager

@contextmanager
def get_db_connection():
    conn = sqlite3.connect('video_notes.db')
    conn.row_factory = sqlite3.Row
    try:
        yield conn
        conn.commit()
    except Exception as e:
        conn.rollback()
        raise e
    finally:
        conn.close()

class NoteRepository:
    def save_note(self, note: Note) -> int:
        with get_db_connection() as conn:
            cursor = conn.cursor()
            if note.id:
                cursor.execute("""
                    UPDATE notes SET content=?, updated_at=datetime('now')
                    WHERE id=?
                """, (note.content, note.id))
                return note.id
            else:
                cursor.execute("""
                    INSERT INTO notes (project_id, content)
                    VALUES (?, ?)
                """, (note.project_id, note.content))
                return cursor.lastrowid

快速上手

安装依赖

git clone https://github.com/Schuyler2025/video-player-note.git
cd video-player-note
pip install -r requirements.txt

启动应用

python main.py

常用快捷键

  • Space - 播放/暂停
  • ← / → - 后退/前进 5 秒
  • Ctrl+T - 插入时间戳
  • Ctrl+N - 新建笔记
  • Ctrl+S - 保存笔记
  • Ctrl+E - 导出笔记

实战场景示例

场景 1:学习算法课程

打开一个排序算法的视频:

00:12 开始讲解冒泡排序原理
冒泡排序通过相邻元素比较和交换来排序...
时间复杂度:O(n²)
空间复杂度:O(1)

05:34 代码实现
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]

复习时,点击 05:34 立即跳转到代码讲解部分,无需拖动进度条。

场景 2:技术会议录像

记录会议亮点:

01:23 产品架构更新 - 微服务改造
新的架构采用 Spring Cloud 全家桶...

15:47 性能优化经验
- 引入 Redis 缓存,响应时间从 500ms 降至 50ms
- 数据库分表分库,QPS 提升 10 倍

28:15 Q&A 环节精彩问答
问:如何处理热点数据?
答:采用多级缓存策略...

以后想回顾某个知识点,点击对应时间戳即可。

项目亮点总结

这个项目虽然不算复杂,但有几个值得学习的地方:

  1. 分层架构清晰:GUI、Service、Repository 各司其职,代码易维护
  2. 用户体验优先:全键盘操作、时间戳跳转、自动保存等细节处理到位
  3. 技术栈成熟:PyQt5 + VLC + SQLite 都是稳定可靠的技术
  4. 可扩展性强:支持导出、项目切换,后续可添加更多功能

未来改进方向

  • 添加 OCR 识别,支持截图并提取文字到笔记
  • 支持语音识别,自动生成字幕并同步到笔记
  • 添加 AI 辅助,智能总结视频内容
  • 支持多人协作,共享笔记和标注

写在最后

这个项目从想法到实现只用了两周时间,但解决了我学习视频时的真实痛点。好工具不一定需要复杂的技术,关键是找到用户的真实需求并优雅地解决它。

如果你也经常需要看视频学习,不妨试试这个应用。项目源码已开源,欢迎 Star 和提 PR。

项目地址:github.com/Schuyler202…

如果觉得对你有帮助,点个赞支持一下吧!