114 lines
2.9 KiB
Elixir
114 lines
2.9 KiB
Elixir
defmodule Reimmich do
|
|
import Reimmich.Sql
|
|
alias Reimmich.{Album, Asset}
|
|
alias Reimmich.Api
|
|
alias Reimmich.ProgressCounter
|
|
|
|
def albums do
|
|
select("id, name, thumbnail_asset_id FROM remote_album_entity")
|
|
|> Enum.map(fn [album_id, name, thumbnail_asset_id] ->
|
|
assets =
|
|
select("asset_id FROM remote_album_asset_entity WHERE album_id='#{album_id}'")
|
|
|> List.flatten()
|
|
|> Enum.map(&asset/1)
|
|
|
|
%Album{name: name, thumbnail: asset(thumbnail_asset_id), assets: assets}
|
|
end)
|
|
end
|
|
|
|
def asset(id) do
|
|
[[filename, checksum, width, height, thumbhash]] =
|
|
select(
|
|
"name, checksum, width, height, thumb_hash FROM remote_asset_entity WHERE id='#{id}'"
|
|
)
|
|
|
|
%Asset{
|
|
filename: filename,
|
|
checksum: checksum,
|
|
width: width,
|
|
height: height,
|
|
thumbhash: thumbhash
|
|
}
|
|
end
|
|
|
|
def match do
|
|
t_start = System.os_time(:second)
|
|
|
|
albums = albums()
|
|
|
|
no_albums = Enum.count(albums)
|
|
no_album_assets = albums |> Enum.flat_map(& &1.assets) |> Enum.count()
|
|
|
|
total = no_albums + no_album_assets
|
|
total_digits = total |> Integer.digits() |> Enum.count()
|
|
|
|
pad = fn n -> to_string(n) |> String.pad_leading(total_digits) end
|
|
|
|
lookup_and_log = fn asset ->
|
|
result = lookup(asset)
|
|
|
|
IO.write("\e[2K\r")
|
|
|
|
if is_nil(result), do: IO.puts("MISS #{asset.filename}")
|
|
|
|
progress = if is_nil(result), do: ProgressCounter.miss(), else: ProgressCounter.hit()
|
|
IO.write("[#{pad.(progress)}/#{total}]")
|
|
|
|
result
|
|
end
|
|
|
|
IO.puts("~> looking up #{total} assets in #{no_albums} albums")
|
|
IO.puts("")
|
|
|
|
albums =
|
|
albums
|
|
|> Enum.map(fn album ->
|
|
album
|
|
|> Map.replace_lazy(:thumbnail, lookup_and_log)
|
|
|> Map.replace_lazy(:assets, &Enum.map(&1, lookup_and_log))
|
|
end)
|
|
|
|
{hit, miss} = ProgressCounter.result()
|
|
|
|
t_lookup = System.os_time(:second)
|
|
|
|
IO.puts("")
|
|
IO.puts("----------------------------------------------------")
|
|
IO.puts("HIT: #{hit}, MISS: #{miss} (took #{fmt_interval(t_start, t_lookup)})")
|
|
IO.puts("")
|
|
IO.puts("~> creating albums")
|
|
IO.puts("")
|
|
|
|
albums
|
|
|> Enum.each(fn album ->
|
|
Api.create_album(album.name, album.assets)
|
|
|> Api.set_album_thumbnail(album.thumbnail)
|
|
|
|
IO.write("\e[2K\r")
|
|
IO.write("CREATE #{album.name}")
|
|
end)
|
|
|
|
t_finish = System.os_time(:second)
|
|
|
|
IO.puts("")
|
|
IO.puts("----------------------------------------------------")
|
|
IO.puts("")
|
|
IO.puts("~> done (took #{fmt_interval(t_start, t_finish)})")
|
|
end
|
|
|
|
defp lookup(%Asset{} = asset) do
|
|
with nil <- Api.find_by(%{checksum: asset.checksum}),
|
|
nil <- Api.find_by(%{originalFileName: asset.filename}) do
|
|
nil
|
|
end
|
|
end
|
|
|
|
defp fmt_interval(t1, t2) do
|
|
seconds = t2 - t1
|
|
|
|
mm = div(seconds, 60) |> to_string() |> String.pad_leading(2, "0")
|
|
ss = rem(seconds, 60) |> to_string() |> String.pad_leading(2, "0")
|
|
|
|
"#{mm}:#{ss}"
|
|
end
|
|
end
|