{"id":21109430,"url":"https://github.com/sachac/subed","last_synced_at":"2026-02-17T01:12:20.074Z","repository":{"id":45025385,"uuid":"190560568","full_name":"sachac/subed","owner":"sachac","description":"subed is a subtitle editor for Emacs","archived":false,"fork":false,"pushed_at":"2026-02-10T20:33:03.000Z","size":1181,"stargazers_count":212,"open_issues_count":15,"forks_count":19,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-02-10T23:41:26.964Z","etag":null,"topics":["emacs-mode","srt","subtitles"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sachac.png","metadata":{"files":{"readme":"README.org","changelog":"NEWS.org","contributing":null,"funding":null,"license":"LICENSES/CC0-1.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.org","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-06-06T10:09:55.000Z","updated_at":"2026-02-10T20:33:04.000Z","dependencies_parsed_at":"2023-01-31T17:15:56.502Z","dependency_job_id":"7d881fee-44e3-4e56-bf70-c7cc0b2e99fd","html_url":"https://github.com/sachac/subed","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/sachac/subed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachac%2Fsubed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachac%2Fsubed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachac%2Fsubed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachac%2Fsubed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sachac","download_url":"https://codeload.github.com/sachac/subed/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sachac%2Fsubed/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29528470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T00:57:22.232Z","status":"ssl_error","status_checked_at":"2026-02-17T00:54:25.811Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs-mode","srt","subtitles"],"created_at":"2024-11-20T00:53:31.966Z","updated_at":"2026-02-17T01:12:20.062Z","avatar_url":"https://github.com/sachac.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+BEGIN_COMMENT\nSPDX-FileCopyrightText: 2019-2021 The subed Authors\n\nSPDX-License-Identifier: GPL-3.0-or-later\n#+END_COMMENT\n\n#+TOC: headlines 2\n\n* subed\n:PROPERTIES:\n:CUSTOM_ID: subed\n:END:\nsubed is an Emacs major mode for editing subtitles while playing the\ncorresponding media file with [[https://mpv.io/][mpv]]. At the moment, the only supported\nformats are:\n\n- SubRip ( ~.srt~)\n- WebVTT ( ~.vtt~ )\n- Advanced SubStation Alpha ( ~.ass~, experimental )\n- Tab-separated values ( ~.tsv~, experimental ) - as exported by\n  Audacity for labels. TSVs are not recognized automatically because\n  it's a common data format, but you can use ~subed-tsv-mode~ to turn\n  it on in a buffer.\n\n[[file:screenshot.jpg]]\n\n#+CAPTION: With word data and waveforms\n[[file:word-data-and-waveform.png]]\n\n** Features\n:PROPERTIES:\n:CUSTOM_ID: subed-features\n:END:\n\n- Jump to next (~M-n~) and previous (~M-p~) subtitle text.\n- Jump to the beginning (~C-M-a~) and end (~C-M-e~) of the current\n  subtitle's text.\n- Merge subtitles with ~M-m~ (~subed-merge-dwim~) and split them with\n  ~M-.~ (~subed-split-subtitle~). If the media file is playing in MPV,\n  use the current playback position. If not, use the relative position\n  in the subtitle text, or other functions listed in\n  ~subed-split-subtitle-timestamp-functions~.\n- Insert subtitles evenly spaced throughout the available space (~M-i~) or\n  right next to the current subtitle (~C-M-i~).  A prefix argument controls how\n  many subtitles to insert and whether they are inserted before or after the\n  current subtitle.\n- Kill subtitles (~M-k~).\n- Adjust subtitle start (~M-[~ / ~M-]~ or ~C-M-[~ / ~C-M-]~ if Emacs lives in a\n  terminal) and stop (~M-{~ / ~M-}~) time.  A prefix argument sets the number of\n  milliseconds for the current session (e.g. ~C-u 1000 M-[ M-[ M-[~ decreases\n  start time by 3 seconds).\n- Move the current subtitle or all marked subtitles\n  (~subed-move-subtitles~) forward (~C-M-n~) or backward (~C-M-p~) in\n  time without changing subtitle duration.  A prefix argument sets the\n  number of milliseconds for the current session (e.g. ~C-u 500 C-M-n\n  C-M-n~ moves the current subtitle 1 second forward).\n- Shift the current subtitle together with all following subtitles\n  using (~subed-shift-subtitles~), or shift them forward (~C-M-f~) or\n  backward (~C-M-b~).  This is basically a convenience shortcut for\n  ~C-SPC M-\u003e C-M-n/p~.  This is handy for correcting sync delays where\n  the subtitles are correctly spaced but are offset from the audio.\n- Scale all subtitles or all marked subtitles forward (~C-M-x~) or backward\n  (~C-M-S-x~) in time without changing subtitle duration.  A prefix argument\n  sets the number of milliseconds for the current session (e.g. ~C-u 500\n  C-M-x~ moves the last [or last marked] subtitle forward 500ms and\n  proportionally scales all [or all marked] subtitles based on this time\n  extension.  Similarly, ~C-u 500 C-M-S-x~ moves the last [or last marked]\n  subtitle backward 500ms and proportionally scales all [or all marked]\n  subtitles based on this time contraction).  This can be extremely useful to\n  correct synchronization issues in existing subtitle files.  First, adjust\n  the starting time if necessary (e.g. ~C-M-f~), then adjust the ending and\n  scale constituent subtitles (e.g. ~C-M-x~).\n- Show CPS (characters per second) for the current subtitle.\n- Insert HTML-like tags (~C-c C-t C-t~, with an optional attribute\n  when prefixed by ~C-u~), in particular italics (~C-c C-t C-i~) or\n  boldface (~C-c C-t C-b~).\n- SRT: Sort and re-number subtitles and remove any extra spaces and\n  newlines (~M-s~). This is done automatically every time the buffer\n  is saved.\n- Trim subtitle overlaps with ~M-x subed-trim-overlaps~. By\n  default, this adjusts the stop time of overlapping subtitles to\n  ~subed-subtitle-spacing~ milliseconds before the next subtitle\n  starts. Use ~M-x customize-group~ ~subed~ to configure trimming\n  to happen automatically when buffers are loaded or saved, which\n  time is adjusted, and how much time to leave between subtitles.\n- Convert between formats with ~M-x subed-convert~.\n- Show the waveform (~M-x subed-waveform-minor-mode~, off by default)\n  extracted from the media file using ~ffmpeg~ with the start/stop\n  positions of the current subtitle and the current position in MPV\n  marked along with the subtitle.  Change the \"volume\" of the waveform\n  (i.e., the /visible/ amplitude) with ~C-c C--~ and ~C-c C-=~.\n  Redisplay the waveform with ~C-c |~.  Left/right-click on the\n  waveform to set the start/stop timestamps. If you would like to display the waveform automatically when you open a file, you can add ~(add-hook 'subed-mode-hook 'subed-waveform-minor-mode)~ to your configuration.  \n- Load word timing data (ex: SRV2) using ~M-x\n  subed-word-data-load-from-file~. This will be used for splitting\n  words at timestamps when available.\n- Use ~M-x subed-align~ and [[https://www.readbeyond.it/aeneas/][aeneas]] to align your text or subtitles\n  with an audio file in order to get timestamps.\n\n*** mpv integration (optional)\n:PROPERTIES:\n:CUSTOM_ID: subed-features-mpv-integration-optional\n:END:\n\nUsing network sockets to control MPV works on Linux and on Mac OS X,\nbut not on Microsoft Windows due to the lack of Unix-style sockets. On\nMicrosoft Windows, you will not be able to synchronize with MPV.\n\n- Automatically open the associated media file in MPV based on the filename, open a media file manually with ~C-c C-v~ (~subed-mpv-play-from-file~), or play media directly from a URL with ~C-c C-u~ (~subed-mpv-play-from-url~) . You can customize the automatic detection of files by changing ~subed-video-extensions~ and ~subed-audio-extensions~.\n- Pause and resume playback without leaving Emacs (~M-SPC~).\n- Jump to the current subtitle in the MPV player with ~M-j~\n  (~subed-mpv-jump-to-current-subtitle~). Toggle looping over the\n  current subtitle with ~C-c C-l~\n  (~subed-toggle-loop-over-current-subtitle~).  Control how many seconds\n  to loop before or after the current subtitles by customizing\n  ~subed-loop-seconds-before~ and ~subed-loop-seconds-after~.\n- Use\n  ~C-c .~ (~subed-toggle-sync-point-to-player~) to toggle whether the point should move to the currently playing subtitle.\n- Use ~C-c ,~ (~subed-toggle-sync-player-to-point~) to toggle whether mpv should seek to the position of the current subtitle when the point moves between subtitles.\n- Subtitles are automatically reloaded in mpv when the buffer is saved.\n- Copy the current playback position as start (~C-c [~) or stop (~C-c ]~)\n  time of the current subtitle.\n- Playback is paused or slowed down when a subtitle's text is edited (~C-c\n  C-p~, ~subed-toggle-pause-while-typing~).\n- Loop over the current subtitle in mpv (~C-c C-l~).\n- When a subtitle's start or stop time changes, mpv seeks to the subtitle's\n  start time (~C-c C-r~, ~subed-toggle-replay-adjusted-subtitle~).\n- Move one frame forward or backward (~C-c C-f .~ and ~C-c C-f ,~;\n  pressing ~,~ or ~.~ afterwards moves by frames until any other\n  key is pressed).\n\n** Installation\n:PROPERTIES:\n:CUSTOM_ID: subed-installation\n:END:\n*** Installing the subed package from NonGNU Elpa\n:PROPERTIES:\n:CUSTOM_ID: subed-installation-installing-the-subed-package-from-nongnu-elpa\n:END:\n~subed~ is now on [[https://elpa.nongnu.org/nongnu/subed.html][NonGNU ELPA]].  On Emacs 28 and later, you can install it with ~M-x package-install~ ~subed~.\n\nTo install it on Emacs 27 or earlier, add the following to your Emacs configuration file:\n\n#+begin_src emacs-lisp :eval no\n(with-eval-after-load 'package (add-to-list 'package-archives '(\"nongnu\" . \"https://elpa.nongnu.org/nongnu/\")))\n#+end_src\n\nUse ~M-x eval-buffer~ to run the code, use ~M-x package-refresh-contents~ to load the package archives, and then use ~M-x package-install~ ~subed~.\n\nSample configuration:\n\n#+begin_src emacs-lisp\n(with-eval-after-load 'subed-mode\n\t;; Remember cursor position between sessions\n\t(add-hook 'subed-mode-hook 'save-place-local-mode)\n\t;; Break lines automatically while typing\n\t(add-hook 'subed-mode-hook 'turn-on-auto-fill)\n\t;; Break lines at 40 characters\n\t(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))\n\t;; Some reasonable defaults\n\t(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)\n\t;; As the player moves, update the point to show the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)\n\t;; As your point moves in Emacs, update the player to start at the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)\n\t;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}\n\t(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)\n\t;; Loop over subtitles\n\t(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)\n\t;; Show characters per second\n\t(add-hook 'subed-mode-hook 'subed-enable-show-cps))\n#+end_src\n\n*** Manual installation\n:PROPERTIES:\n:CUSTOM_ID: subed-installation-manual-installation\n:END:\n\nIf that doesn't work, you can install it manually. To install from the main branch:\n\n#+begin_src sh :eval no\ngit clone https://github.com/sachac/subed.git\n#+end_src\n\nThis will create a =subed= directory with the code.\n\nIf you have the =make= utility, you can regenerate the autoload definitions with\n\n#+begin_src sh :eval no\nmake autoloads\n#+end_src\n\nIf you don't have =make= installed, you can generate the autoloads\nwith:\n\n#+begin_src sh :eval no\nemacs --quick --batch --eval \"(progn (setq generated-autoload-file (expand-file-name \\\"subed-autoloads.el\\\" \\\"subed\\\") backup-inhibited t) \\\n\t(update-directory-autoloads \\\"./subed\\\"))\"\n#+end_src\n\nThen you can add\nthe following to your Emacs configuration (typically\n=~/.config/emacs/init.el=, =~/.emacs.d/init.el=, or =~/.emacs=; you\ncan create this file if it doesn't exist yet). Here's a configuration example:\n\n#+begin_src emacs-lisp\n;; Note the reference to the subed subdirectory, instead of the one at the root of the checkout\n(add-to-list 'load-path \"/path/to/subed/subed\")\n(require 'subed-autoloads)\n\n(with-eval-after-load 'subed-mode\n\t;; Remember cursor position between sessions\n\t(add-hook 'subed-mode-hook 'save-place-local-mode)\n\t;; Break lines automatically while typing\n\t(add-hook 'subed-mode-hook 'turn-on-auto-fill)\n\t;; Break lines at 40 characters\n\t(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))\n\t;; Some reasonable defaults\n\t(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)\n\t;; As the player moves, update the point to show the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)\n\t;; As your point moves in Emacs, update the player to start at the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)\n\t;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}\n\t(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)\n\t;; Loop over subtitles\n\t(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)\n\t;; Show characters per second\n\t(add-hook 'subed-mode-hook 'subed-enable-show-cps))\n#+end_src\n\nYou can reload your configuration with =M-x eval-buffer= or restart Emacs.\n\nIf you want to try a branch (ex: =derived-mode=), you can use the\nfollowing command inside the =subed= directory:\n\n#+begin_src sh :eval no\ngit checkout branchname\n#+end_src\n*** use-package configuration\n:PROPERTIES:\n:CUSTOM_ID: subed-installation-use-package-configuration\n:END:\n\nHere's an example setup if you use [[https://github.com/jwiegley/use-package][use-package]]:\n\n#+BEGIN_SRC emacs-lisp\n(use-package subed\n\t:ensure t\n\t:config\n\t;; Remember cursor position between sessions\n\t(add-hook 'subed-mode-hook 'save-place-local-mode)\n\t;; Break lines automatically while typing\n\t(add-hook 'subed-mode-hook 'turn-on-auto-fill)\n\t;; Break lines at 40 characters\n\t(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))\n\t;; Some reasonable defaults\n\t(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)\n\t;; As the player moves, update the point to show the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)\n\t;; As your point moves in Emacs, update the player to start at the current subtitle\n\t(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)\n\t;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}\n\t(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)\n\t;; Loop over subtitles\n\t(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)\n\t;; Show characters per second\n\t(add-hook 'subed-mode-hook 'subed-enable-show-cps)\n\t)\n#+END_SRC\n\n*** straight configuration\n:PROPERTIES:\n:CUSTOM_ID: subed-installation-straight-configuration\n:END:\n\nIf you use [[https://github.com/radian-software/straight.el][straight.el]], you can install subed with the following recipe:\n\n#+begin_src emacs-lisp\n(straight-use-package '(subed :type git :host github :repo \"sachac/subed\" :files (\"subed/*.el\")))\n#+end_src\n\n** Getting started\n:PROPERTIES:\n:CUSTOM_ID: subed-getting-started\n:END:\n\n~C-h f subed-mode~ should get you started. This is the parent mode for\n~subed-srt-mode~, ~subed-vtt-mode~, and ~subed-ass-mode~. When\nmanually loading a mode, use those specific format modes instead of\n~subed-mode~.\n** Some workflow ideas\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas\n:END:\n*** Editing subtitles\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-editing-subtitles\n:END:\n\nYou can use ~subed-mpv-jump-to-current-subtitle~ (~M-j~) to play the current\nsubtitle and use ~subed-mpv-toggle-pause~ (~M-SPC~) to stop at the right time.\nUse ~subed-toggle-loop-over-current-subtitle~ (~C-c C-l~) if you want to keep\nlooping automatically.\n\nIf you have wdiff installed, you can use\n~subed-wdiff-subtitle-text-with-file~ to compare the subtitle text\nwith a script or another subtitle file.\n\n*** Writing subtitles from scratch\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-writing-subtitles-from-scratch\n:END:\n\nOne way is to start with one big subtitle that covers the whole media\nfile. You can create this manually by using the media file duration or a very large ending timestamp (ex: 24:00:000), or you can use ~M-x subed-insert-subtitle-for-whole-file~.\nUse ~C-c C-p~ (~subed-toggle-pause-while-typing~) to enable pausing while typing. Start playback with ~M-SPC~ (~subed-mpv-toggle-pause~), type as you listen, and split using using ~subed-split-subtitle~ (~M-.~).\n\nAnother way is to type as much of the text as you can without worrying\nabout timestamps, putting each caption on a separate line. Then you\ncan use ~subed-align~ to convert it into timestamped captions.\n\n*** Starting from auto-generated YouTube captions\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-starting-from-auto-generated-youtube-captions\n:END:\n\nTo download autogenerated captions for one of the\nvideos you've uploaded to YouTube:\n\n1. Go to https://studio.youtube.com\n2. Click on Content in the left-side menu, find your video, and edit it. Clicok on Subtitles in the left menu. If automatic subtitles are available, you will see them in the Subtitles column in the middle.\n   - If you don't see automatic subtitles, set\n     your video's language in the Details tab,\n     wait a while, and check again.\n3. Hover over the \"Published\" label and use the\n   three-dot menu to download the SRT. (The VTT\n   file has a lot of extra mark-up.)\n4. Open the SRT file. subed can synchronize\n   playback as you edit the subtitle file. If the\n   media has the same base filename as the\n   subtitle file, it will be opened automatically.\n   If not, use ~subed-mpv-play-from-file~ (~C-c\n   C-v~) or ~subed-mpv-play-from-url~ (~C-c C-u~).\n\nYou may want to use ~M-x subed-trim-overlaps~ to remove the overlaps between subtitles.\n\nIf you download the VTT from YouTube, you can load\nthe word timing data from it with ~M-x\nsubed-word-data-load-from-file~. Then those times\nwill be used when splitting subtitles with\n~subed-split-subtitle~..\n\nIf you want to work in the VTT format so you can\nuse comments, convert the SRT with ~M-x\nsubed-convert~.\n\nTo upload edited subtitles:\n\n1. Edit your video's details. Click on Subtitles on the right side.\n2. Click on the three-dot menu.\n3. Click on \"Upload file\", choose \"With timing\", and click on \"Continue\".\n4. Select your file.\n\n*** Reflowing subtitles into shorter or longer lines\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-reflowing-subtitles-into-shorter-or-longer-lines\n:END:\n\nYou may want to use ~set-fill-column~ and\n~display-fill-column-indicator-mode~ to show the target number of\ncharacters.\n\nUse ~subed-split-subtitle~ (~M-.~), ~subed-merge-dwim~ (~M-b~), and\n~subed-merge-with-previous~ (~M-M~) to split lines.\n\nSplitting will use the current MPV position if available. If not, it\nwill guess where to split based on the the number of characters in the\nsubtitle. You can use ~subed-mpv-jump-to-current-subtitle~ (~M-j~) to play the\ncurrent subtitle manually and use ~subed-mpv-toggle-pause~ (~M-SPC~) to stop at\nthe right time. Use ~subed-toggle-loop-over-current-subtitle~ (~C-c C-l~) if you\nwant to keep looping. ~subed-waveform-show-current~ can help you\nfine-tune the split.\n\n*** Adjusting timestamps\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-adjusting-timestamps\n:END:\n\nYou can use ~subed-mpv-jump-to-current-subtitle~ (~M-j~) to play the\ncurrent subtitle manually. Use\n~subed-mpv-jump-to-current-subtitle-near-end~ (~M-J~) to jump to near\nthe end of the subtitle in order to test it. Use\n~subed-toggle-loop-over-current-subtitle~ (~C-c C-l~) if you want to\nkeep looping automatically. Use ~subed-mpv-toggle-pause~ (~M-SPC~) to stop at the\nright time.\n\nYou can also manually adjust\n\n- subtitle start: ~M-[~  / ~M-]~\n- subtitle stop: (~M-{~ / ~M-}~)\n\nA prefix argument sets the number of milliseconds (e.g. ~C-u 1000 M-[ M-[ M-[~ decreases start time by 3 seconds).\n\nRodrigo Morales also has some functions for [[https://rodrigo.morales.pe/2024/11/17/my-subed-configuration-for-adding-subtitles-to-emacsconf-2024/][playing part of the subtitles and changing them by a little bit]].\n\nYou can shift subtitles to start at a specific\ntimestamp with\n~subed-shift-subtitles-to-start-at-timestamp~ . To\nuse a millisecond offset instead, use\n~subed-shift-subtitles~.\n\n**** Waveforms\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-adjusting-timestamps-waveforms\n:END:\n\nUse ~subed-waveform-show-current~ or ~subed-waveform-show-all~ together with FFmpeg\nto display waveforms for subtitles.\n\nUse ~subed-waveform-set-start~ (~mouse-1~, which\nis left click) or ~subed-waveform-set-stop~\n(~mouse-3~, which is right-click) to adjust only\nthe current subtitle's timestamps, or use\n~subed-waveform-set-start-and-copy-to-previous~\n(~S-mouse-1~ or ~M-mouse-1~) or\n~subed-waveform-set-stop-and-copy-to-next~\n(~S-mouse-3~ or ~M-mouse-3~) to adjust adjacent\nsubtitles as well.\n\nYou can use ~M-mouse-2~ (Meta-middle-click, ~subed-waveform-shift-subtitles~) to shift the current subtitle and succeeding subtitles so that they start at the position you clicked on.\n\n**** A transient map for retiming subtitles\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-adjusting-timestamps-a-transient-map-for-retiming-subtitles\n:END:\n\nYou can use ~subed-retime-subtitles~ to set new\ntimes for subtitles by pressing ~SPC~ when the\ncurrent subtitle should stop. It will start with\nthe current subtitle and then continue until you\npress a key that is not in the temporary keymap.\n\nKeys:\n\n| ~SPC~                   | set stop and move forward |\n| ~\u003cleft\u003e~ or ~j~         | replay current subtitle   |\n| ~\u003cright\u003e~ or ~n~ or ~f~ | next                      |\n| ~b~                     | back                      |\n| ~p~                     | pause                     |\n\n**** Aeneas forced alignment tool\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-adjusting-timestamps-aeneas-forced-alignment-tool\n:END:\n\nThe [[https://www.readbeyond.it/aeneas/][aeneas forced alignment tool]] (Python) can take\na media file and a text file (one cue per line) or\nsubtitle file, and create a subtitle file with the\ntimings determined by matching synthesized speech\nwith the waveforms.\n\nTo use Aeneas to re-time subtitles or text, install\nAeneas and its prerequisites, then call ~M-x\nsubed-align~ to align the entire buffer.\n\nYou can also select a region and then use ~M-x\nsubed-align-region~ to recalculate the timestamps\nfor just that region. One way to use this is:\n\n1. Determine the last correctly-timed subtitle. We'll call this subtitle A. Go to the beginning of subtitle A and use ~C-SPC~ (~set-mark-command~) to set the mark.\n2. Pick a subtitle in the incorrectly-timed section. We'll call this subtitle B. Use ~subed-mpv-jump-to-current-subtitle~ to seek to that position. Play it and listen for the words. If you can't figure out which subtitle matches the position currently being played, choose a different subtitle starting point B until you find one that's recognizable.\n3. Reset the playback position by using ~subed-mpv-jump-to-current-subtitle~ on subtitle B.\n4. Now look for the subtitle that matches the words you heard at the playback position for subtitle B. We'll call that one subtitle D.\n5. Go to the subtitle before subtitle D. We'll call that subtitle C. Use ~C-c ]~ (~subed-copy-player-pos-to-stop-time~) to set the stop time of subtitle C (the one immediately before D) to the playback position, which is the same time as the incorrect starting time for subtitle B.\n6. Go to the end of subtitle C.\n7. Use ~M-x subed-align-region~ to recalculate the timestamps within that section.\n\nAeneas tends to have trouble with subtitle times\nwhere there are long silences, background noises,\ninaccurate transcripts (especially where the\nspeaker has skipped or added many words),\noverlapping speakers, and non-English languages.\nIt may take several tries to figure out a span of\nsubtitles where Aeneas is more accurate.\nDoublechecking with the word timing data can help\nquickly verify if the subtitle times are\nreasonable.\n\n**** Word timing data\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-adjusting-timestamps-word-timing-data\n:END:\n\nTo use word timing data from something like\nWhisperX, load subed-word-data.el and then use\n~subed-word-data-load-from-file~. The word times\nwill then be used when you split subtitles with\n~subed-split-subtitle~.\n\n*** Exporting text for review\n:PROPERTIES:\n:CUSTOM_ID: subed-some-workflow-ideas-exporting-text-for-review\n:END:\n\nYou can use ~subed-copy-region-text~ to copy the text of the subtitles\nfor pasting into another buffer. Call it with the universal prefix\n~C-u~ to copy comments as well.\n\nYou can also use ~subed-convert~ to convert subtitles to a text file.\n\n** Troubleshooting\n:PROPERTIES:\n:CUSTOM_ID: subed-troubleshooting\n:END:\n*** subed-mpv: Service name too long\n:PROPERTIES:\n:CUSTOM_ID: subed-troubleshooting-subed-mpv-service-name-too-long\n:END:\n\nIf =subed-mpv-client= reports =(error \"Service name too long\")=, this\nis probably because the path to the socket used to communicate with\nMPV is too long for your operating system. You can use =M-x customize=\nto set =subed-mpv-socket-dir= to a shorter path.\n\n** Important change in v1.0.0\n:PROPERTIES:\n:CUSTOM_ID: subed-important-change-in-v1-0-0\n:END:\n\n~subed~ now uses ~subed-srt-mode~, ~subed-vtt-mode~, and\n~subed-ass-mode~ instead of directly using ~subed-mode~. These modes\nshould be automatically associated with the ~.vtt~, ~.srt~, and ~.ass~\nextensions. If the generic ~subed-mode~ is loaded instead of the format-specific mode,\nyou may get an error such as:\n\n#+begin_example\nError in post-command-hook (subed--post-command-handler): (cl-no-applicable-method subed--subtitle-id)\n#+end_example\n\nIf you set ~auto-mode-alist~ manually in your config, please make sure\nyou associate extensions the appropriate format-specific mode instead\nof ~subed-mode~. The specific backend functions (ex:\n~subed-srt--jump-to-subtitle-id~) are also deprecated in favor of\nusing generic functions such as ~subed-jump-to-subtitle-id~.\n\n** Testing\n:PROPERTIES:\n:CUSTOM_ID: subed-testing\n:END:\n\nYou'll need to install the =buttercup= and =package-lint= Emacs packages. You'll also need =GNU Make= so that you can work with Makefiles. To run the tests, use the command =make test=.\n\nTo re-run tests automatically when files change, something like nodemon might be helpful.\n\n#+begin_src sh :eval no\nnodemon -w tests/*.el -w subed/*.el -x \"make test\"\n#+end_src\n\n** Contributions\n:PROPERTIES:\n:CUSTOM_ID: subed-contributions\n:END:\n   Contributions would be really appreciated! subed conforms to the [[https://reuse.software/spec/][REUSE\n   Specification]]; this means that every file has copyright and license\n   information. If you modify a file, please update the year shown after\n   ~SPDX-FileCopyrightText~. Thank you!\n\n   There's a list of authors in the file ~AUTHORS.org~. If you have at any point\n   contributed to subed, you are most welcome to add your name (and email\n   address if you like) to the list.\n\n** License\n:PROPERTIES:\n:CUSTOM_ID: subed-license\n:END:\n   subed is free software: you can redistribute it and/or modify it under the\n   terms of the GNU General Public License as published by the Free Software\n   Foundation, either version 3 of the License, or (at your option) any later\n   version.\n\n   This program is distributed in the hope that it will be useful but WITHOUT\n   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n   FOR A PARTICULAR PURPOSE.  See the [[https://www.gnu.org/licenses/gpl-3.0.txt][GNU General Public License]] for more\n   details.\n* Build tips\n:PROPERTIES:\n:CUSTOM_ID: build-tips\n:END:\n\nHere's a post-commit hook that will make it easier to remember to tag releases:\n\n#+begin_src python :eval no\n#!/usr/bin/python\n\n# place in .git/hooks/post-commit\n# Based on https://gist.github.com/ajmirsky/1245103\n\nimport subprocess\nimport re\n\nprint(\"checking for version change...\",)\n\noutput = subprocess.check_output(['git', 'diff', 'HEAD^', 'HEAD', '-U0']).decode(\"utf-8\")\n\nversion_info = None\nfor d in output.split(\"\\n\"):\n    rg = re.compile(r'\\+(?:;;\\s+)?Version:\\s+(?P\u003cmajor\u003e[0-9]+)\\.(?P\u003cminor\u003e[0-9]+)\\.(?P\u003crev\u003e[0-9]+)')\n    m = rg.search(d)\n    if m:\n        version_info = m.groupdict()\n        break\n\nif version_info:\n    tag = \"v%s.%s.%s\" % (version_info['major'], version_info['minor'], version_info['rev'])\n    existing = subprocess.check_output(['git', 'tag']).decode(\"utf-8\").split(\"\\n\")\n    if tag in existing:\n        print(\"%s is already tagged, not updating\" % tag)\n    else:\n        result = subprocess.run(['git', 'tag', '-f', tag])\n        if result.returncode:\n            raise Exception('tagging not successful: %s %s' % (result.stdout, result.returncode))\n        print(\"tagged revision: %s\" % tag)\nelse:\n    print(\"none found.\")\n#+end_src\n\n* Other resources\n:PROPERTIES:\n:CUSTOM_ID: other-resources\n:END:\n\n- [[https://rodrigo.morales.pe/2024/11/17/my-subed-configuration-for-adding-subtitles-to-emacsconf-2024/][My subed customizations for editing captions of Emacsconf 2024 – Rodrigo Morales]]\n- [[https://sachachua.com/blog/category/subed][Sacha Chua's subed-related blog posts]]\n- [[https://mbork.pl/2023-09-18_Making_Anki_flashcards_from_subtitles][Marcin Borkowski: 2023-09-18 Making Anki flashcards from subtitles]]\n- [[https://github.com/sachac/subed-record][sachac/subed-record: Record audio in segments and compile it into a file]]\n- [[https://emacsconf.org/captioning/][EmacsConf -  Captioning tips]]\n\n#+STARTUP: showeverything\n#+OPTIONS: num:nil\n#+OPTIONS: ^:{}\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsachac%2Fsubed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsachac%2Fsubed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsachac%2Fsubed/lists"}