diff --git a/lib/pinchflat/metadata/metadata_file_helpers.ex b/lib/pinchflat/metadata/metadata_file_helpers.ex
index c4320fa..b728f47 100644
--- a/lib/pinchflat/metadata/metadata_file_helpers.ex
+++ b/lib/pinchflat/metadata/metadata_file_helpers.ex
@@ -124,6 +124,21 @@ defmodule Pinchflat.Metadata.MetadataFileHelpers do
end
end
+ @doc """
+ Attempts to determine the season and episode number from a media filepath.
+
+ Returns {:ok, {binary(), binary()}} | {:error, :indeterminable}
+ """
+ def season_and_episode_from_media_filepath(media_filepath) do
+ # matches s + 1 or more digits + e + 1 or more digits (case-insensitive)
+ season_episode_regex = ~r/s(\d+)e(\d+)/i
+
+ case Regex.scan(season_episode_regex, media_filepath) do
+ [[_, season, episode] | _] -> {:ok, {season, episode}}
+ _ -> {:error, :indeterminable}
+ end
+ end
+
defp generate_filepath_for(database_record, filename) do
Path.join([
metadata_directory_for(database_record),
diff --git a/lib/pinchflat/metadata/nfo_builder.ex b/lib/pinchflat/metadata/nfo_builder.ex
index 3db237f..38a26dd 100644
--- a/lib/pinchflat/metadata/nfo_builder.ex
+++ b/lib/pinchflat/metadata/nfo_builder.ex
@@ -6,8 +6,8 @@ defmodule Pinchflat.Metadata.NfoBuilder do
import Pinchflat.Utils.XmlUtils, only: [safe: 1]
- alias Pinchflat.Metadata.MetadataFileHelpers
alias Pinchflat.Utils.FilesystemUtils
+ alias Pinchflat.Metadata.MetadataFileHelpers
@doc """
Builds an NFO file for a media item (read: single "episode") and
@@ -15,12 +15,12 @@ defmodule Pinchflat.Metadata.NfoBuilder do
Returns the filepath of the NFO file.
"""
- def build_and_store_for_media_item(filepath, metadata) do
- nfo = build_for_media_item(metadata)
+ def build_and_store_for_media_item(nfo_filepath, metadata) do
+ nfo = build_for_media_item(nfo_filepath, metadata)
- FilesystemUtils.write_p!(filepath, nfo)
+ FilesystemUtils.write_p!(nfo_filepath, nfo)
- filepath
+ nfo_filepath
end
@doc """
@@ -37,10 +37,15 @@ defmodule Pinchflat.Metadata.NfoBuilder do
filepath
end
- defp build_for_media_item(metadata) do
+ defp build_for_media_item(nfo_filepath, metadata) do
upload_date = MetadataFileHelpers.parse_upload_date(metadata["upload_date"])
+ # NOTE: the filepath here isn't the path of the media item, it's the path that
+ # the NFO should be saved to. This works because the NFO's path is the same as
+ # the media's path, just with a different extension. If this ever changes I'll
+ # need to pass in the media item's path as well.
+ {season, episode} = determine_season_and_episode_number(nfo_filepath, upload_date)
+
# Cribbed from a combination of the Kodi wiki, ytdl-nfo, and ytdl-sub.
- # WHO NEEDS A FANCY XML PARSER ANYWAY?!
"""
@@ -49,8 +54,8 @@ defmodule Pinchflat.Metadata.NfoBuilder do
#{safe(metadata["id"])}
#{safe(metadata["description"])}
#{safe(upload_date)}
- #{safe(upload_date.year)}
- #{Calendar.strftime(upload_date, "%m%d")}
+ #{safe(season)}
+ #{episode}
YouTube
"""
@@ -67,4 +72,11 @@ defmodule Pinchflat.Metadata.NfoBuilder do
"""
end
+
+ defp determine_season_and_episode_number(filepath, upload_date) do
+ case MetadataFileHelpers.season_and_episode_from_media_filepath(filepath) do
+ {:ok, {season, episode}} -> {season, episode}
+ {:error, _} -> {upload_date.year, Calendar.strftime(upload_date, "%m%d")}
+ end
+ end
end
diff --git a/test/pinchflat/metadata/metadata_file_helpers_test.exs b/test/pinchflat/metadata/metadata_file_helpers_test.exs
index 36db3cd..b1b8b2b 100644
--- a/test/pinchflat/metadata/metadata_file_helpers_test.exs
+++ b/test/pinchflat/metadata/metadata_file_helpers_test.exs
@@ -11,6 +11,16 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do
{:ok, %{media_item: media_item}}
end
+ describe "metadata_directory_for/1" do
+ test "returns the metadata directory for the given record", %{media_item: media_item} do
+ base_metadata_directory = Application.get_env(:pinchflat, :metadata_directory)
+
+ metadata_directory = Helpers.metadata_directory_for(media_item)
+
+ assert metadata_directory == Path.join([base_metadata_directory, "media_items", "#{media_item.id}"])
+ end
+ end
+
describe "compress_and_store_metadata_for/2" do
test "returns the filepath", %{media_item: media_item} do
metadata_map = %{"foo" => "bar"}
@@ -142,13 +152,20 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do
end
end
- describe "metadata_directory_for/1" do
- test "returns the metadata directory for the given record", %{media_item: media_item} do
- base_metadata_directory = Application.get_env(:pinchflat, :metadata_directory)
+ describe "season_and_episode_from_media_filepath/1" do
+ test "returns a season and episode if one can be determined" do
+ assert {:ok, {"1", "2"}} = Helpers.season_and_episode_from_media_filepath("/foo/s1e2 - test.mp4")
+ assert {:ok, {"1", "2"}} = Helpers.season_and_episode_from_media_filepath("/foo/S1E2 - test.mp4")
+ assert {:ok, {"001", "002"}} = Helpers.season_and_episode_from_media_filepath("/foo/s001e002 - test.mp4")
+ assert {:ok, {"1", "2"}} = Helpers.season_and_episode_from_media_filepath("/foo/s1e2bar - test.mp4")
+ assert {:ok, {"1", "2"}} = Helpers.season_and_episode_from_media_filepath("/foo/bar s1e2 - test.mp4")
+ end
- metadata_directory = Helpers.metadata_directory_for(media_item)
-
- assert metadata_directory == Path.join([base_metadata_directory, "media_items", "#{media_item.id}"])
+ test "returns an error if a season and episode can't be determined" do
+ assert {:error, :indeterminable} = Helpers.season_and_episode_from_media_filepath("/foo/test.mp4")
+ assert {:error, :indeterminable} = Helpers.season_and_episode_from_media_filepath("/foo/s1 - test.mp4")
+ assert {:error, :indeterminable} = Helpers.season_and_episode_from_media_filepath("/foo/s1e - test.mp4")
+ assert {:error, :indeterminable} = Helpers.season_and_episode_from_media_filepath("/foo/s1etest.mp4")
end
end
end
diff --git a/test/pinchflat/metadata/nfo_builder_test.exs b/test/pinchflat/metadata/nfo_builder_test.exs
index c8b032a..47217c7 100644
--- a/test/pinchflat/metadata/nfo_builder_test.exs
+++ b/test/pinchflat/metadata/nfo_builder_test.exs
@@ -5,7 +5,7 @@ defmodule Pinchflat.Metadata.NfoBuilderTest do
alias Pinchflat.Utils.FilesystemUtils
setup do
- filepath = FilesystemUtils.generate_metadata_tmpfile(:json)
+ filepath = FilesystemUtils.generate_metadata_tmpfile(:nfo)
on_exit(fn -> File.rm!(filepath) end)
@@ -45,6 +45,43 @@ defmodule Pinchflat.Metadata.NfoBuilderTest do
assert String.contains?(nfo, "hello' & <world>")
end
+
+ test "uses the season and episode number from the filepath if it can be determined" do
+ metadata = %{
+ "title" => "title",
+ "uploader" => "uploader",
+ "id" => "id",
+ "description" => "description",
+ "upload_date" => "20210101"
+ }
+
+ tmpfile_directory = Application.get_env(:pinchflat, :tmpfile_directory)
+ filepath = Path.join([tmpfile_directory, "foo/s0123e456.nfo"])
+
+ result = NfoBuilder.build_and_store_for_media_item(filepath, metadata)
+ nfo = File.read!(result)
+
+ assert String.contains?(nfo, "0123")
+ assert String.contains?(nfo, "456")
+
+ File.rm!(filepath)
+ end
+
+ test "uses the upload date if the season and episode number can't be determined", %{filepath: filepath} do
+ metadata = %{
+ "title" => "title",
+ "uploader" => "uploader",
+ "id" => "id",
+ "description" => "description",
+ "upload_date" => "20210101"
+ }
+
+ result = NfoBuilder.build_and_store_for_media_item(filepath, metadata)
+ nfo = File.read!(result)
+
+ assert String.contains?(nfo, "2021")
+ assert String.contains?(nfo, "0101")
+ end
end
describe "build_and_store_for_source/2" do