GithubHelp home page GithubHelp logo

subed's Introduction

subed

subed is an Emacs major mode for editing subtitles while playing the corresponding media file with mpv. At the moment, the only supported formats are:

  • SubRip ( .srt)
  • WebVTT ( .vtt )
  • Advanced SubStation Alpha ( .ass, experimental )
  • Tab-separated values ( .tsv, experimental ) - as exported by Audacity for labels. TSVs are not recognized automatically because it’s a common data format, but you can use subed-tsv-mode to turn it on in a buffer.

https://raw.githubusercontent.com/sachac/subed/master/screenshot.jpg

Features

  • Jump to next (M-n) and previous (M-p) subtitle text.
  • Jump to the beginning (C-M-a) and end (C-M-e) of the current subtitle’s text.
  • Merge subtitles with M-m (subed-merge-dwim) and split them with M-. (subed-split-subtitle). If the media file is playing in MPV, use the current playback position. If not, use the relative position in the subtitle text, or other functions listed in subed-split-subtitle-timestamp-functions.
  • Insert subtitles evenly spaced throughout the available space (M-i) or right next to the current subtitle (C-M-i). A prefix argument controls how many subtitles to insert and whether they are inserted before or after the current subtitle.
  • Kill subtitles (M-k).
  • Adjust subtitle start (M-[ / M-]) and stop (M-{ / M-}) time. A prefix argument sets the number of milliseconds for the current session (e.g. C-u 1000 M-[ M-[ M-[ decreases start time by 3 seconds).
  • Move the current subtitle or all marked subtitles (subed-move-subtitles) forward (C-M-n) or backward (C-M-p) in time without changing subtitle duration. A prefix argument sets the number of milliseconds for the current session (e.g. C-u 500 C-M-n C-M-n moves the current subtitle 1 second forward).
  • Shift the current subtitle together with all following subtitles using (subed-shift-subtitles), or shift them forward (C-M-f) or backward (C-M-b). This is basically a convenience shortcut for C-SPC M-> C-M-n/p. This is handy for correcting sync delays where the subtitles are correctly spaced but are offset from the audio.
  • Scale all subtitles or all marked subtitles forward (C-M-x) or backward (C-M-S-x) in time without changing subtitle duration. A prefix argument sets the number of milliseconds for the current session (e.g. C-u 500 C-M-x moves the last [or last marked] subtitle forward 500ms and proportionally scales all [or all marked] subtitles based on this time extension. Similarly, C-u 500 C-M-S-x moves the last [or last marked] subtitle backward 500ms and proportionally scales all [or all marked] subtitles based on this time contraction). This can be extremely useful to correct synchronization issues in existing subtitle files. First, adjust the starting time if necessary (e.g. C-M-f), then adjust the ending and scale constituent subtitles (e.g. C-M-x).
  • Show CPS (characters per second) for the current subtitle.
  • Insert HTML-like tags (C-c C-t C-t, with an optional attribute when prefixed by C-u), in particular italics (C-c C-t C-i) or boldface (C-c C-t C-b).
  • SRT: Sort and re-number subtitles and remove any extra spaces and newlines (M-s). This is done automatically every time the buffer is saved.
  • Trim subtitle overlaps with M-x subed-trim-overlaps. By default, this adjusts the stop time of overlapping subtitles to subed-subtitle-spacing milliseconds before the next subtitle starts. Use M-x customize-group subed to configure trimming to happen automatically when buffers are loaded or saved, which time is adjusted, and how much time to leave between subtitles.
  • Convert between formats with M-x subed-convert.
  • Show the waveform (M-x subed-waveform-minor-mode, off by default) extracted from the media file using ffmpeg with the start/stop positions of the current subtitle and the current position in MPV marked along with the subtitle. Change the “volume” of the waveform (i.e., the visible amplitude) with C-c C-- and C-c C-=. Redisplay the waveform with C-c |. Left/right-click on the 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.
  • Load word timing data (ex: SRV2) using M-x subed-word-data-load-from-file. This will be used for splitting words at timestamps when available.
  • Use M-x subed-align and aeneas to align your text or subtitles with an audio file in order to get timestamps.

mpv integration (optional)

Using network sockets to control MPV works on Linux and on Mac OS X, but not on Microsoft Windows due to the lack of Unix-style sockets. On Microsoft Windows, you will not be able to synchronize with MPV.

  • 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.
  • Pause and resume playback without leaving Emacs (M-SPC).
  • Jump to the current subtitle in the MPV player with M-j (subed-mpv-jump-to-current-subtitle). Toggle looping over the current subtitle with C-c C-l (subed-toggle-loop-over-current-subtitle). Control how many seconds to loop before or after the current subtitles by customizing subed-loop-seconds-before and subed-loop-seconds-after.
  • Use C-c . (subed-toggle-sync-point-to-player) to toggle whether the point should move to the currently playing subtitle.
  • 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.
  • Subtitles are automatically reloaded in mpv when the buffer is saved.
  • Copy the current playback position as start (C-c [) or stop (C-c ]) time of the current subtitle.
  • Playback is paused or slowed down when a subtitle’s text is edited (C-c C-p, subed-toggle-pause-while-typing).
  • Loop over the current subtitle in mpv (C-c C-l).
  • When a subtitle’s start or stop time changes, mpv seeks to the subtitle’s start time (C-c C-r, subed-toggle-replay-adjusted-subtitle).
  • Move one frame forward or backward (C-c C-f . and C-c C-f ,~; pressing ~,~ or ~. afterwards moves by frames until any other key is pressed).

Installation

Installing the subed package from NonGNU Elpa

subed is now on NonGNU ELPA. On Emacs 28 and later, you can install it with M-x package-install subed.

To install it on Emacs 27 or earlier, add the following to your Emacs configuration file:

(with-eval-after-load 'package (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/")))

Use 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.

Sample configuration:

(with-eval-after-load 'subed-mode
	;; Remember cursor position between sessions
	(add-hook 'subed-mode-hook 'save-place-local-mode)
	;; Break lines automatically while typing
	(add-hook 'subed-mode-hook 'turn-on-auto-fill)
	;; Break lines at 40 characters
	(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))
	;; Some reasonable defaults
	(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)
	;; As the player moves, update the point to show the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)
	;; As your point moves in Emacs, update the player to start at the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)
	;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}
	(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)
	;; Loop over subtitles
	(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)
	;; Show characters per second
	(add-hook 'subed-mode-hook 'subed-enable-show-cps))

Manual installation

If that doesn’t work, you can install it manually. To install from the main branch:

git clone https://github.com/sachac/subed.git

This will create a subed directory with the code.

If you have the make utility, you can regenerate the autoload definitions with

make autoloads

If you don’t have make installed, you can generate the autoloads with:

emacs --quick --batch --eval "(progn (setq generated-autoload-file (expand-file-name \"subed-autoloads.el\" \"subed\") backup-inhibited t) \
	(update-directory-autoloads \"./subed\"))"

Then you can add the following to your Emacs configuration (typically ~/.config/emacs/init.el, ~/.emacs.d/init.el, or ~/.emacs; you can create this file if it doesn’t exist yet). Here’s a configuration example:

;; Note the reference to the subed subdirectory, instead of the one at the root of the checkout
(add-to-list 'load-path "/path/to/subed/subed")
(require 'subed-autoloads)

(with-eval-after-load 'subed-mode
	;; Remember cursor position between sessions
	(add-hook 'subed-mode-hook 'save-place-local-mode)
	;; Break lines automatically while typing
	(add-hook 'subed-mode-hook 'turn-on-auto-fill)
	;; Break lines at 40 characters
	(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))
	;; Some reasonable defaults
	(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)
	;; As the player moves, update the point to show the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)
	;; As your point moves in Emacs, update the player to start at the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)
	;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}
	(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)
	;; Loop over subtitles
	(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)
	;; Show characters per second
	(add-hook 'subed-mode-hook 'subed-enable-show-cps))

You can reload your configuration with M-x eval-buffer or restart Emacs.

If you want to try a branch (ex: derived-mode), you can use the following command inside the subed directory:

git checkout branchname

use-package configuration

Here’s an example setup if you use use-package:

(use-package subed
	:ensure t
	:config
	;; Remember cursor position between sessions
	(add-hook 'subed-mode-hook 'save-place-local-mode)
	;; Break lines automatically while typing
	(add-hook 'subed-mode-hook 'turn-on-auto-fill)
	;; Break lines at 40 characters
	(add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40)))
	;; Some reasonable defaults
	(add-hook 'subed-mode-hook 'subed-enable-pause-while-typing)
	;; As the player moves, update the point to show the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-point-to-player)
	;; As your point moves in Emacs, update the player to start at the current subtitle
	(add-hook 'subed-mode-hook 'subed-enable-sync-player-to-point)
	;; Replay subtitles as you adjust their start or stop time with M-[, M-], M-{, or M-}
	(add-hook 'subed-mode-hook 'subed-enable-replay-adjusted-subtitle)
	;; Loop over subtitles
	(add-hook 'subed-mode-hook 'subed-enable-loop-over-current-subtitle)
	;; Show characters per second
	(add-hook 'subed-mode-hook 'subed-enable-show-cps)
	)

straight configuration

If you use straight.el, you can install subed with the following recipe:

(straight-use-package '(subed :type git :host github :repo "sachac/subed" :files ("subed/*.el")))

Getting started

C-h f subed-mode should get you started. This is the parent mode for subed-srt-mode, subed-vtt-mode, and subed-ass-mode. When manually loading a mode, use those specific format modes instead of subed-mode.

Some workflow ideas

Reflowing subtitles into shorter or longer lines

You may want to use set-fill-column and display-fill-column-indicator-mode to show the target number of characters.

Use subed-split-subtitle (M-.), subed-merge-dwim (M-b), and subed-merge-with-previous (M-M) to split lines.

Splitting will use the current MPV position if available. If not, it will guess where to split based on the the number of characters in the subtitle. You can use subed-mpv-jump-to-current-subtitle (M-j) to play the current subtitle manually and use subed-mpv-toggle-pause (M-SPC) to stop at the right time. Use subed-toggle-loop-over-current-subtitle (C-c C-l) if you want to keep looping. subed-waveform-show-current can help you fine-tune the split.

Adjusting timestamps

You can use subed-mpv-jump-to-current-subtitle (M-j) to play the current subtitle manually. Use subed-mpv-jump-to-current-subtitle-near-end (M-J) to jump to near the end of the subtitle in order to test it. Use subed-toggle-loop-over-current-subtitle (C-c C-l) if you want to keep looping automatically. Use subed-mpv-toggle-pause (M-SPC) to stop at the right time.

subed-waveform-show-current or subed-waveform-show-all can be useful for adjusting start and end timestamps. Use subed-waveform-set-start (mouse-1, which is left click) or subed-waveform-set-stop (mouse-3, which is right-click) to adjust only the current subtitle’s timestamps, or use subed-waveform-set-start-and-copy-to-previous (S-mouse-1 or M-mouse-1) or subed-waveform-set-stop-and-copy-to-next (S-mouse-3 or M-mouse-3) to adjust adjacent subtitles as well.

You can also manually adjust

  • subtitle start: M-[ / M-]
  • subtitle stop: (M-{ / M-})

A prefix argument sets the number of milliseconds (e.g. C-u 1000 M-[ M-[ M-[ decreases start time by 3 seconds).

Editing subtitles

You can use subed-mpv-jump-to-current-subtitle (M-j) to play the current subtitle and use subed-mpv-toggle-pause (M-SPC) to stop at the right time. Use subed-toggle-loop-over-current-subtitle (C-c C-l) if you want to keep looping automatically.

If you have wdiff installed, you can use subed-wdiff-subtitle-text-with-file to compare the subtitle text with a script or another subtitle file.

Writing subtitles from scratch

One way is to start with one big subtitle that covers the whole media file, and then split it using subed-split-subtitle (M-.).

Another way is to type as much of the text as you can without worrying about timestamps, putting each caption on a separate line. Then you can use subed-align to convert it into timestamped captions.

Resynchronizing subtitles

If you’re using subed-waveform-show-current or subed-waveform-show-all, you 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.

To do this with the keyboard, you can use subed-shift-subtitles-to-start-at-timestamp if you want to specify a timestamp or subed-shift-subtitles to specify a millisecond offset.

Exporting text for review

You can use subed-copy-region-text to copy the text of the subtitles for pasting into another buffer. Call it with the universal prefix C-u to copy comments as well.

Troubleshooting

subed-mpv: Service name too long

If subed-mpv-client reports (error "Service name too long"), this is probably because the path to the socket used to communicate with MPV is too long for your operating system. You can use M-x customize to set subed-mpv-socket-dir to a shorter path.

Important change in v1.0.0

subed now uses subed-srt-mode, subed-vtt-mode, and subed-ass-mode instead of directly using subed-mode. These modes should be automatically associated with the .vtt, .srt, and .ass extensions. If the generic subed-mode is loaded instead of the format-specific mode, you may get an error such as:

Error in post-command-hook (subed--post-command-handler): (cl-no-applicable-method subed--subtitle-id)

If you set auto-mode-alist manually in your config, please make sure you associate extensions the appropriate format-specific mode instead of subed-mode. The specific backend functions (ex: subed-srt--jump-to-subtitle-id) are also deprecated in favor of using generic functions such as subed-jump-to-subtitle-id.

Contributions

Contributions would be really appreciated! subed conforms to the REUSE Specification; this means that every file has copyright and license information. If you modify a file, please update the year shown after SPDX-FileCopyrightText. Thank you!

There’s a list of authors in the file AUTHORS.org. If you have at any point contributed to subed, you are most welcome to add your name (and email address if you like) to the list.

License

subed is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

Other resources

subed's People

Contributors

brownts avatar dylanjm avatar i-blis avatar jun0 avatar mbork avatar riscy avatar rndusr avatar sachac avatar seabass-labrax avatar twlz0ne avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

subed's Issues

How to insert a new subtitle that begin at the actual timestamp of mpv?

I don't know if I understand badly how to use subed or if it is a missing feature.

For example, I open a .srt file and load the video.
There are some subtitles for the first minute of the video.

I press M-SPC to play the video for 2 minutes.

Then I pause the video and I want to insert a subtitle that starts at 2 minutes (the actual timestamp of mpv).

Is it possible to do this?

Each time I use M-i, subed add a new subtitle that starts at the end of the last subtitle (plus a given length) and backward the video accordingly.

Describe workflow for writing new subtitles?

The README seems geared towards editing existing subtitles. It would be nice if there was a section there to describe what the typical workflow would be when writing brand new subtitles: I've played around with the mode for fifteen minutes, and I don't think I've quite understood how this mode is to be used efficiently.

Invalid function error in subed-waveform-toggle-show-all

subed 1.2.11
Emacs 29.1
Debian Bookworm 12.4

When I call subed-waveform-toggle-show-all I get the error message

subed-waveform-add-to-all: Invalid function: subed-for-each-subtitle

This error doesn't occur if I either

  • open subed-waveform.el and recompile subed-waveform-add-to-all; or
  • delete file subed-waveform.elc

If I byte-recompile subed-waveform I get, between a lot of similar warnings, the following one

subed-waveform.el:475:4: Warning: the function ‘subed-for-each-subtitle’ is
    not known to be defined.

And when I use waveform after that, the error appears again.

org-links to subtitles by number

not sure if this is poss, and it's not super important.

at the moment, running org-store-link link on a subtitle number treats that number as a line number in the file, which gives you a link to somewhere else.

although, running it on the first line of your subtitle text should mostly work, provided the text is unique...

Adopt REUSE standard for copyright and licensing

Hello @rndusr! Thank you for creating subed; it has been very useful to me. I have written some patches for it that @sachac suggested might improve subed for other users as well.

While writing these, I noticed that subed doesn't include full copyright and license information. This is very important in free software licensing audits, for instance to check license compatibility or to properly credit the authors of a file that you want to copy.

I would like to suggest adopting the REUSE standard for this. As someone who has does several such audits for my entries to the Free Software Directory, I can personally vouch for the utility of REUSE! With compliance to the REUSE specification, all files have header comments containing the full copyright and SPDX license identifier, and all the relevant licenses are stored in a LICENSES/ directory. This means that all of the information needed to reuse the code for another program is there in the header.

I have added REUSE headers as best I can using the information in the Git log; I'll attach my pull request here. Before merging my changes, however, there are a few things that need to be done.

We need to ask all of the contributors to subed to confirm that they hold the copyright to their edits and didn't copy them from another project (if so the copyright notices would need to be changed to reflect that). If you give the 'green light' I'll mention their names so that they can confirm that here in this issue.

Secondly, please could you confirm that the Git history hasn't been changed? Similarly, that might require a change to the copyright notices.

And finally, there is the screenshot.png file - I have taken the liberty to label this as CC0-1.0 as it contains a frame from a film, and CC0 explicitly disclaims all responsibility for any other copyrighted material (section 4c). Please don't merge my changes unless you want to waive your image into the public domain! I have been using subed to add captions to a friend's conference talk (which is under a GPL-friendly license) so I can take a screenshot of that if you would like to replace the image with something that is definitely free to use here.

I'm looking forward to your response! :)

Default faces clash with different theme styles

Currently, the face colors are hard-coded to different color values. This is causing a theme clash with my emacs config. Also, for some reason "brightyellow" doesn't show up as a color in my Emacs 28.0.50. I recommend changing the default face values to inherit from the font-lock family of faces.

Here is an example of what I'm talking about:

image

How to read a property from mpv

Mpv's JSON IPC documentation describes getting replies, such as with the command get_property. Browsing in subed's code for examples, I was surprised subed doesn't rely on reading properties to work, rather its reply handling seems to be built around events (subed-mpv--client-filter and subed-mpv--client-handle-*). In summary I couldn't find examples of getting a property from mpv, so I'm asking here how to do that.

An extension I'm making to the subed package needs to read a few properties from mpv. subed-mpv--client-send can send commands to the JSON IPC, but I just can't figure out how to send a command and see the reply, or e.g. put in a variable.

To give some more background, this is a function in what I'm working on. For now, the function get_property is a placeholder.

(defun subed-mpv--extract-current ()
  "This function returns the full text of an embedded subtitle track currently selected in mpv.
   I made this because embedded subs are very common, and I don't want to extract them manually
   just to be able to see the file in Emacs."
  (let ((trackno (get_property "current-tracks/sub/ff-index"))
        (subformat (get_property "current-tracks/sub/codec"))
        (container-path (get_property "path")))
    (shell-command-to-string
        (concat
            "ffmpeg -nostdin -loglevel error -i " container-path
            " -c:s copy -map :" trackno " -f " subformat " pipe:"))))

Find overlapping timestamps when sanitizing

subed should now properly prevent overlapping subtitles while editing, but it
will still load a file with illegal timestamps.

Sanitizing should report:

  • Subtitles that have a larger start time than their stop time.

  • Subtitles that have a larger stop time than the next subtitle's start time, if
    there is a next subtitle.

Should this be implemented generically for all subtitle formats?

I'm not familiar with any subtitle formats besides SubRip. If all widely used
formats have the same concept of start/stop timestamps per subtitle, these
checks should probably be implemented generically.

subed-mpv--socket: Couldn’t make directory /scp:edrx@linode:/tmpsubed

Hi Sacha!

I copied a .vtt file to a remote directory using tramp, and then
opened the remote .vtt... and when I tried to kill its buffer I got
this error:

File error: Couldn’t make directory /scp:edrx@linode:/tmpsubed
subed-mpv--socket: Couldn’t make directory /scp:edrx@linode:/tmpsubed

It became unkillable! =(

Remember positions between editing sessions

When closing a buffer in subed-mode, store point, video file and playback position somewhere (Where?) and associate it with the subtitle file's path. When subed-mode is entered, check if these things can be restored.

This feature should have a defcustom to turn it off.

Describe workflow for converting a series of lines like "2:34 foo bar" to subtitles?

Hi subed people,

this is similar to Issue 15, but different enough to deserve a new thread...

So, question: I am learning subed now. I have subtitles for parts of some videos in an improvised format - in which each line is just a timestamp followed by text, like this: "14:01 So I took a look at the man page for xpdf" - and I would like to use subed to convert that to the SRT format. I can try to write a Lua script to do that conversion for me, but is there a more subed-ish way to do that? Here is a VERY rough idea to start with: we would use a keyboard macro that supposes that we are in a two-window setting with .srt at the left and the improvised subtitles at the right; each time that we run the keyboard macro it would run `subed-insert-subtitle' in the .srt window, copy one line from the right window to the left window, and it would somehow use my timestamp - the "14:01" in the sample line above - to set up the start and the stop time of the subtitle...

My problem is with the step "and it would somehow use my timestamp" above, of course. Besides that I was mind-blown by how easy it was to set up subed here... really, really, really good job, Random User, Sacha, and others! =)

Btw, here is an example of these improvised subtitles: http://angg.twu.net/emacsconf2019.html

Define `subed-loop-seconds-before` and `subed-loop-seconds-after` in millisecond?

As I was using the looping-over feature of subed heavily to practice English shadowing (as I described in /r/emacs),
I noticed that there is an additional second by default added to before and after the loop, as specified by
subed-loop-seconds-before and subed-loop-seconds-after.

Since video timestamps are usually in milliseconds, I think it's better to define them in milliseconds,
as opposed to seconds.

But to be compatible, it may be tedious to achieve it if we decide to do so.

(At first, I setq both of them to 0. Last night, but I thought I'd better have an extra time of 200ms,
then I (setq subed-loop-seconds-after 200) and the looping didn't stop.
I didn't realize what was wrong until a few moments ago😂)

Also, I think maybe we could only provide one customizable variable like subed-loop-milliseconds-gap,
as there isn't much difference between before and after regarding a loop.

What do you think?

(error "Found invalid start time: \"00:00:00.000 --> 00:00:03.400\"")

I encountered this error when editing subtitle generated by Buzz (powered by OpenAI Whisper C++ version)

https://github.com/chidiwilliams/buzz

WEBVTT

00:00:00.000 --> 00:00:03.520
Mac Power Users Episode 592

00:00:03.520 --> 00:00:06.400
WWDC 2021

00:00:06.400 --> 00:00:08.400
in the future of Mac Automation.

00:00:08.400 --> 00:00:18.200
Hello and welcome back to Mac Power Users.

00:00:18.200 --> 00:00:19.560
My name is Stephen Hackett.

Could you help me out? Thank you very much.

Debugger entered--Lisp error: (error "Found invalid start time: \"00:00:00.000 --> 00:00:...")
  signal(error ("Found invalid start time: \"00:00:00.000 --> 00:00:..."))
  error("Found invalid start time: %S" "00:00:00.000 --> 00:00:03.400")
  #f(compiled-function () #<bytecode -0x1c5a20884d25afc1>)()
  apply(#f(compiled-function () #<bytecode -0x1c5a20884d25afc1>) nil)
  subed-validate-format()
  subed--sort()
  subed-sort()
  run-hooks(subed-sanitize-functions)
  subed--sanitize()
  subed-sanitize()
  subed-prepare-to-save()
  run-hooks(before-save-hook)
  basic-save-buffer(nil)
  save-buffer()
  #f(compiled-function (buffer) #<bytecode 0x8c750db36c52b8a>)(#<buffer mpu592.srt>)
  map-y-or-n-p(#f(compiled-function (buffer) #<bytecode 0x386155ccd182e70>) #f(compiled-function (buffer) #<bytecode 0x8c750db36c52b8a>) (#<buffer mpu592.srt>) ("buffer" "buffers" "save") ((18 #f(compiled-function (buf) #<bytecode -0x13c75ba9d05c38a4>) "view this buffer") (6 #f(compiled-function (buf) #<bytecode 0x81e69c181c6e49c>) "view this buffer and quit") (100 #f(compiled-function (buf) #<bytecode -0x24c8ee819382ae6>) "view changes in this buffer")))
  save-some-buffers(:no-prompt #f(compiled-function () #<bytecode 0x1165867bd47a6294>))
  apply(save-some-buffers (:no-prompt #f(compiled-function () #<bytecode 0x1165867bd47a6294>)))
  timer-event-handler([t 0 5 0 :repeat save-some-buffers (:no-prompt #f(compiled-function () #<bytecode 0x1165867bd47a6294>)) idle 0 nil])

macOS 13.0.1
Emacs-plus: GNU Emacs 29.0.50 (build 1, aarch64-apple-darwin22.1.0, NS appkit-2299.00
Version 13.0.1 (Build 22A400)) of 2022-11-23

adjust time of current subtitle end and next subtitle start?

is this actually possible in subed at the moment?

it's great to not allow individual overlaps, but often it means you can't adjust the end of a time stamp without first adjusting the start of the next, so you have to work out of order.

you'd want to do this without touching any subsequent subs also.

More feature integration with mpv

Despite being alpha, subed is a pleasure to use. I've even never had any crash yet. Thanks for creating it :)

I've been tinkering with your code, to discover that most of what I needed was already baked in. I still had a couple of requirements to ease my workflow and hacked a couple of functions out. There are certainly not worth a PR but I am sharing them nonetheless.

1. Insert mpv player's current timestamp as current subtitle's stop timestamp

This is pretty useful when after creating the sub at a given point, you let the video flow and stop it where the subtitle should disappear.

(defun ego/subed-insert-player-stop-timestamp ()
  "Replace current subtitle's stop timestamp with mpv player's current timestamp."
  (interactive)
  (subed-srt--jump-to-subtitle-time-stop)
  (when (and subed-mpv-playback-position
	     (looking-at subed-srt--regexp-timestamp))
    (replace-match (subed-srt--msecs-to-timestamp subed-mpv-playback-position))
    (subed--run-subtitle-time-adjusted-hook)))

I never needed the same for the start timestamp yet.

2. Amend current start and stop timestamp to match previous one

When adding a new subtitle between two existing ones, I mostly need it to be next to the previous one, as if I created it at the end of the file. Currently subed fits smartly the newly created subs between the two. Meaning that, if I add a single one, it will match the next sub's time stamp. The following function allows the change the timestamp to make it fit the previous one.

(defun ego/subed-have-current-sub-timestamp-match-previous ()
  "Changes the current start and stop timestamp to match the previous one according to default spacing and length settings"
  (interactive)
  (let* ((current-id  (subed-srt--subtitle-id))
	 (previous-id (- current-id 1)))
    (when (> previous-id 0)
      (subed-srt--jump-to-subtitle-id previous-id)
      (let* ((prev-stop-ts (subed-srt--subtitle-msecs-stop))
	     (new-start-ts (+ prev-stop-ts subed-subtitle-spacing)))
	(subed-srt--jump-to-subtitle-id current-id)
	(subed-srt--jump-to-subtitle-time-start)
	(when (looking-at subed-srt--regexp-timestamp)
	  (replace-match (subed-srt--msecs-to-timestamp new-start-ts))
	  (subed-srt--jump-to-subtitle-time-stop)
	  (when (looking-at subed-srt--regexp-timestamp)
	    (replace-match (subed-srt--msecs-to-timestamp
			    (+ new-start-ts (* 1000 subed-default-subtitle-length)))))
	  (subed--run-subtitle-time-adjusted-hook))))))

3. Insert subtitle with player's timestamp

This one is particularly useful for inserting a subtitle at the end, when you skipped a long way forward without subtitles.

(defun ego/subed-insert-with-player-timestamp ()
  (interactive)
  (when-let* ((current-position subed-mpv-playback-position))
    (subed-srt--jump-to-subtitle-id)
    (subed-srt--jump-to-subtitle-end)
    (forward-line)
    (insert "\n")
    (insert (format "0\n%s --> %s\n\n\n"
                    (subed-srt--msecs-to-timestamp current-position)
                    (subed-srt--msecs-to-timestamp (+ current-position
						      (* 1000 subed-default-subtitle-length)))))
    (subed-srt--sort) ;; regenerate-ids seems to be enough in all cases, still keeping it
    ;; (subed-srt--regenerate-ids)
    (subed-srt--jump-to-subtitle-text)))

I also made basic commands to rewind and forward mpv frame by frame.

Probably most of them are not worth incorporating to subed but who knows. I thought it might be useful to share them.

I'd be happy to contribute, if you open issues with new feature requests for instance. I can provide one of these as a PR if needed.

subed-increase-start-time breaks if start-time >= end-time

I was frustrated when I couldn't use M-] to move a subtitle into the right position because the end-time was also incorrect. subed mode refused to let me set the start and end times to be the same values. I then tried to move the end time, but couldn't because it would've been greater than the next start time.

I'd rather subed let me do something "wrong" and presume that I know what I'm doing and I'm going to fix it later. If I do something silly, subed can syntax highlight in RED background times which are impossible (start >= end, end > next start).

Even better would be to have new functions that moves both the start and end times and bind those functions to M-[, M-] by default. Here's what I'd suggest for bindings:

  • M-[, M-] Move both (easiest to type as it doesn't require shift)
  • M-{, M-} Move end times (already bound this way)
  • M-(, M-) Move start times (analogous to M-{ as it also uses the shift key)

Thank you for creating this neat mode.

subed recenters on save, breaking scroll-all-mode

first, thx for your great package, it's nifty as.

so subed recenters, or rather scrolls so that point is 4/5 down the frame, on save. i guess in its sanitizing of things.

i didn't mind it all that much until i started using scroll-all-mode, which allows you to synchronize the scrolling of two windows. using it with subed, you can align the scrolling of two subtitles files, for translating. but when i save my srt file, only one of the windows gets recentered, putting the synchronized scroll out of sync.

it's not a killer issue, but perhaps it's also simple to avoid?

update: hm maybe scroll-all-mode is just too bare bones, as it really ought to work with recenter, which emacs calls the "basic scrolling command"(!). perhaps some subed users have an alternative approach for synchronized scrolling?

i guess scroll-syncing the subtitles by their numbers would be a colossal effort? that would be killer, but i'm not sure how it could be done.

Can't select "mov" files

Thank you for providing this amazing tool. Only issue I'm running into is I can't seem to see MOV files when trying to open a local file. Potentially an mpv limitation, but I can open MOV files directly with mpv, so I'm not sure. Any chance this is a known issue? Thanks much!

The looping over period of timestamp do not change instantly after merge with the next subtitle.

For intance, there are two subtitles:

33
00:03:16,820 --> 00:03:18,560
passenger volumes haven't been as high

34
00:03:18,560 --> 00:03:21,519
as expected with only 84 000 people

When cursor is at numerical order 33 and subed-toggle-loop-over-current-subtitle is ture, MPV loop over the time period of 00:03:16,820 --> 00:03:18,560.
Then call subed-merge-dwin, then 34 will be merged into 33, so 33 is going to be:

33
00:03:16,820 --> 00:03:21,519
passenger volumes haven't been as high
as expected with only 84 000 people

But MPV is still looping over the old time period 00:03:16,820 --> 00:03:18,560, no the new one 00:03:16,820 --> 00:03:21,519.

This behavior do not abide the function name subed-toggle-loop-over-current-subtitle.

Versus reverse, the command subed-merge-with-previous behaves what I expected,
after merged with previous subtitle, the looping over period is changed instantly to the new merged subtile's start and end timestamp.

Wishlist: Increase, decrease all times within region

If a bunch of subtitles (or the entire file) are all off by the same amount, it could be handy if we could shift them simultaneously. I could see activating this if the Transient Mark is active or if the user typed C-u followed by a subed-shift-* command. (Similar to how C-u C-/ performs undo only in the current region).

subed fails to open the corresponding video file automatically

Somehow there is a tiny issue that subed fails to open the corresponding video file automatically sometimes,
I don't know how to reproduce it yet, but it doesn't bother me too much as I can open the video file via C-c C-v, so this is a low priority problem.

How to use subed-scale-subtitles-forward?

Hi,

I have a question (well 2 actually) regarding how to use C-M-x subed-scale-subtitles-forward. My intention was to "slide" all subtitles in the buffer to the right with some offset in timeline, so that it would be in sync with the video.

Here is a minimal srt subtile file:

1
00:00:00,496 --> 00:00:02,457
blah blah blah

2
00:00:11,846 --> 00:00:13,807
blah blah blah

3
00:00:23,196 --> 00:00:25,157
blah blah blah

I have two questions in fact:

  1. Why is there no effect on the first subtitle, when I type C-M-x? (all other subtitles' timestamps are increased)

  2. The delta on the start/end times are 50ms, although subed-milliseconds-adjust is 100, why is that?

    Ah, I found that the delta would be half of subed-milliseconds-adjust, is it by design?

subed version: 1.0.24, with commitid 7842bb9f15f08ea3d223f98bf7be98d6d01be522

How to use IINA with subed?

https://github.com/iina/iina

IINA is based on mpv, build for macOS, and it claims

All mpv options are supported here, except those starting with "--no-".
Example: --mpv-volume=20 --mpv-resume-playback=no`
iina --help    
Usage: iina-cli [arguments] [files] [-- mpv_option [...]]

Arguments:
--mpv-*:
        All mpv options are supported here, except those starting with "--no-".
        Example: --mpv-volume=20 --mpv-resume-playback=no
--separate-windows | -w:
        Open all files in separate windows.
--stdin, --no-stdin:
        You may also pipe to stdin directly. Sometimes iina-cli can detect whether
        stdin has file, but sometimes not. Therefore it's recommended to always
        supply --stdin when piping to iina, and --no-stdin when you are not intend
        to use stdin.
--keep-running:
        Normally iina-cli launches IINA and quits immediately. Supply this option
        if you would like to keep it running until the main application exits.
--pip:
        Enter Picture-in-Picture after opening the media.
--help | -h:
        Print this message.

mpv Option:
Raw mpv options without --mpv- prefix. All mpv options are supported here.
Example: --volume=20 --no-resume-playback

Fancy overwrite-mode when point is on a timestamp

It would be convenient if a timestamp could be edited by just typing the new digits without removing the old ones, i.e. what overwrite-mode (bound to Insert by default) does.

Point could also automatically skip over colons and the comma in a timestamp so that you can move point to the beginning of "00:00:00,000", type "123456789" and it would result in "12:34:56,789".

Essentially, it should be impossible to make the timestamp invalid while in subed-mode, and it should be very quick to navigate to and within timestamps and changing them.

Implementation

Text properties or overlays should make this possible, but I have no idea how exactly.

Maybe a function in modification_hooks? For overlays, these are called both before and after a buffer change. But that seems quite complicated.

There is already subed-point-motion-hook, which could be used to determine if point is on a timestamp and enable or disable overlay-mode accordingly.

Maybe it's possible to use the cursor-intangible property to implement the skipping of ":" and ","?

Is it a good idea to apply properties when loading a file or does that take too many resources? Would it be possible to add/remove properties as they come into view?

Or should there be a special mode for editing the timestamps of the current subtitle that can be enabled with a key? For example, M-RET moves point to the beginning of the start time and creates an overlay. If point is already on the start time, M-RET moves point to the stop time. If point is already on the stop time, move back to the text or original position.

saving subed buffer removes flyspell overlays

not sure if others have this issue.

when i save a subed buffer, all flyspell underlines disappear, which means i have to keep running flyspell-buffer to see them again, even when flyspell-mode is enabled.

High CPU load when playing through long gap between subtitles

How To Reproduce
  1. Place point on a subtitle that doesn't have a following subtitle for a few
    minutes.

  2. M-x subed-enable-sync-point-to-player

  3. Let the video play.

  4. After a while (tens of seconds in my case), CPU load on a single core spikes
    to 100%. Eventually, video playback becomes choppy and Emacs takes several
    seconds to respond to user input.

What I Know

The relevant code seems to be in subed-srt--subtitle-id-at-msecs, specifically
in the final (catch 'subtitle-id ...). If I comment that out, the issue goes
away, but I don't understand what's wrong with the code or how to investigate
further.

Wishlist: Please loop region by default

I don't understand why subed keeps playing video beyond the subtitle while I'm typing it in. It seems like the video should either stop or it should loop. I use C-c C-l to make it loop, which is handy, but seems like it ought to be the default. Thanks.

Debugger entered--Lisp error: (void-variable subed--init-alist)

Expected Behavior

No error occurs at startup.

Actual Behavior

void-variable subed--init-alist occurs at startup.

Extra details

Debugger entered--Lisp error: (void-variable subed--init-alist)
Debug on Error enabled globally
Package cl is deprecated
Debugger entered--Lisp error: (void-variable subed--init-alist)
  (let ((--dolist-tail-- subed--init-alist)) (while --dolist-tail-- (let ((item (car --dolist-tail--))) (let ((file-ext-regex (car item))) (add-to-list 'auto-mode-alist (cons (concat "\\." file-ext-regex "\\'") 'subed-mode))) (setq --dolist-tail-- (cdr --dolist-tail--)))))
  eval-buffer(#<buffer  *load*> nil "/Users/*/.emacs.d/elpa/subed-20201228.50..." nil t)  ; Reading at buffer position 954
  load-with-code-conversion("/Users/*/.emacs.d/elpa/subed-20201228.50..." "/Users/*/.emacs.d/elpa/subed-20201228.50..." nil t)
  load("/Users/*/.emacs.d/elpa/subed-20201228.50..." nil t)
  package--activate-autoloads-and-load-path(#s(package-desc :name subed :version (20201228 505) :summary "A major mode for editing subtitles" :reqs ((emacs (25 1))) :kind nil :archive nil :dir "/Users/*/.emacs.d/elpa/subed-20201228.50..." :extras ((:url . "https://github.com/rndusr/subed") (:keywords "convenience" "files" "hypermedia" "multimedia")) :signed nil))
  package--load-files-for-activation(#s(package-desc :name subed :version (20201228 505) :summary "A major mode for editing subtitles" :reqs ((emacs (25 1))) :kind nil :archive nil :dir "/Users/*/.emacs.d/elpa/subed-20201228.50..." :extras ((:url . "https://github.com/rndusr/subed") (:keywords "convenience" "files" "hypermedia" "multimedia")) :signed nil) nil)
  package-activate-1(#s(package-desc :name subed :version (20201228 505) :summary "A major mode for editing subtitles" :reqs ((emacs (25 1))) :kind nil :archive nil :dir "/Users/*/.emacs.d/elpa/subed-20201228.50..." :extras ((:url . "https://github.com/rndusr/subed") (:keywords "convenience" "files" "hypermedia" "multimedia")) :signed nil) nil deps)
  package-activate(subed)
  package--activate-all()
  package-activate-all()
  package-initialize()
  (progn (toggle-debug-on-error) (setq user-emacs-directory "~/.emacs.d/") (setq package-user-dir (expand-file-name "elpa/" user-emacs-directory)) (package-initialize))
  eval((progn (toggle-debug-on-error) (setq user-emacs-directory "~/.emacs.d/") (setq package-user-dir (expand-file-name "elpa/" user-emacs-directory)) (package-initialize)) t)
  command-line-1(("--eval" "\n(progn\n  (toggle-debug-on-error)\n  (setq user-ema..."))
  command-line()
  normal-top-level()

Steps to reproduce

>  ls ~/.emacs.d/elpa/subed-20201228.505/
subed-autoloads.el  subed-common.elc  subed-config.elc  subed-debug.elc  subed-mpv.elc  subed-srt.el   subed-vtt.el   subed.el
subed-common.el     subed-config.el   subed-debug.el    subed-mpv.el     subed-pkg.el   subed-srt.elc  subed-vtt.elc  subed.elc

⋊>  emacs -nw -Q --eval "
     (progn
       (toggle-debug-on-error)
       (setq user-emacs-directory \"~/.emacs.d/\")
       (setq package-user-dir (expand-file-name \"elpa/\" user-emacs-directory))
       (package-initialize))
     " --batch

Environment

  • macOS 10.12.6
  • Emacs 27.1&28.0
  • subed-20201228.505

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.