diff --git a/README.md b/README.md index 2e43779..6f93b57 100644 --- a/README.md +++ b/README.md @@ -35,16 +35,33 @@ iex> vtt = """ Hello world! """ ...> Vttyl.parse(vtt) |> Enum.into([]) -[%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!"}] +[%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!", voice: nil}] ``` #### Stream Parsing ```elixir iex> "same_text.vtt" |> File.stream!([], 2048) |> Vttyl.parse_stream() |> Enum.into([]) -[%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!"}] +[%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!", voice: nil}] ``` +#### Simple Voice Spans + +(Closing voice spans are currently not supported) + +```elixir +iex> vtt = """ + WEBVTT + + 1 + 00:00:15.450 --> 00:00:17.609 + Hello world! + """ +...> Vttyl.parse(vtt) |> Enum.into([]) +[%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!", voice: "Andy"}] +``` + + ### Encoding Vttyl also supports encoding parts. @@ -60,6 +77,17 @@ Hello world! """ ``` +```elixir +iex> parts = [%Vttyl.Part{end: 17609, part: 1, start: 15450, text: "Hello world!", voice: "Andy"}] +...> Vttyle.encode(parts) +""" +WEBVTT +1 +00:00:15.450 --> 00:00:17.609 +Hello world! +""" +``` + ## License Vttyl is Copyright © 2019 Grain Intelligence, Inc. It is free software, and may be diff --git a/config/config.exs b/config/config.exs index 2a6eea0..becde76 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,30 +1 @@ -# This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. -use Mix.Config - -# This configuration is loaded before any dependency and is restricted -# to this project. If another project depends on this project, this -# file won't be loaded nor affect the parent project. For this reason, -# if you want to provide default values for your application for -# third-party users, it should be done in your "mix.exs" file. - -# You can configure your application as: -# -# config :vttyl, key: :value -# -# and access this configuration in your application as: -# -# Application.get_env(:vttyl, :key) -# -# You can also configure a third-party app: -# -# config :logger, level: :info -# - -# It is also possible to import configuration files, relative to this -# directory. For example, you can emulate configuration per environment -# by uncommenting the line below and defining dev.exs, test.exs and such. -# Configuration from the imported file will override the ones defined -# here (which is why it is important to import them last). -# -# import_config "#{Mix.env()}.exs" +import Config diff --git a/lib/vttyl/decode.ex b/lib/vttyl/decode.ex index 46df131..3e39fcc 100644 --- a/lib/vttyl/decode.ex +++ b/lib/vttyl/decode.ex @@ -25,7 +25,8 @@ defmodule Vttyl.Decode do # Text content should be on one line and the other stuff should have appeared not is_nil(acc.part) and not is_nil(acc.start) and not is_nil(acc.end) and line != "" -> - %Part{acc | text: line} + {voice, text} = parse_text(line) + %Part{acc | text: text, voice: voice} true -> acc @@ -59,6 +60,14 @@ defmodule Vttyl.Decode do Regex.match?(@line_regex, line) end + defp parse_text(" line) do + [voice, text] = String.split(line, ">", parts: 2) + voice = String.split(voice, " ") |> List.last() + {voice, text} + end + + defp parse_text(text), do: {nil, text} + defp parse_timestamps(line) do line |> String.split("-->") diff --git a/lib/vttyl/encode.ex b/lib/vttyl/encode.ex index 76d8bba..8bb3ba5 100644 --- a/lib/vttyl/encode.ex +++ b/lib/vttyl/encode.ex @@ -1,10 +1,19 @@ defmodule Vttyl.Encode do @moduledoc false + alias Vttyl.Part @spec encode_part(Part.t(), :vtt | :srt) :: String.t() def encode_part(part, type) do ts = fmt_timestamp(part.start, type) <> " --> " <> fmt_timestamp(part.end, type) - Enum.join([part.part, ts, part.text], "\n") + + text = + if type == :vtt && part.voice do + "" <> part.text + else + part.text + end + + Enum.join([part.part, ts, text], "\n") end @hour_ms 3_600_000 diff --git a/lib/vttyl/part.ex b/lib/vttyl/part.ex index 9b801f3..f31f8b0 100644 --- a/lib/vttyl/part.ex +++ b/lib/vttyl/part.ex @@ -3,7 +3,8 @@ defmodule Vttyl.Part do part: non_neg_integer(), start: millisecond :: integer, end: millisecond :: integer, - text: String.t() + text: String.t(), + voice: String.t() | nil } - defstruct [:start, :end, :text, :part] + defstruct [:start, :end, :text, :part, :voice] end diff --git a/priv/samples/voice.vtt b/priv/samples/voice.vtt new file mode 100644 index 0000000..da471c4 --- /dev/null +++ b/priv/samples/voice.vtt @@ -0,0 +1,17 @@ +WEBVTT + +1 +00:00.000 --> 00:02.000 +It’s a blue apple tree! + +2 +00:02.000 --> 00:04.000 +No way! + +3 +00:04.000 --> 00:06.000 +Hee! + +4 +00:06.000 --> 00:08.000 +That’s awesome! diff --git a/test/vttyl_test.exs b/test/vttyl_test.exs index ada2a06..f9b76d2 100644 --- a/test/vttyl_test.exs +++ b/test/vttyl_test.exs @@ -79,6 +79,18 @@ defmodule VttylTest do assert length(parsed) == 20 end + + test "voice spans" do + parsed = + "voice.vtt" + |> get_vtt_file() + |> File.stream!([], 2048) + |> Vttyl.parse_stream() + |> Stream.map(& &1.voice) + |> Enum.into([]) + + assert ["Esme", "Mary", "Esme", "Mary"] == parsed + end end describe "encode_vtt/1" do