Current section

Files

Jump to
ex_video_factory lib ex_video_factory.ex
Raw

lib/ex_video_factory.ex

defmodule ExVideoFactory do
@moduledoc """
Elixir wrapper for France**Télévisions** Video Factory API.
"""
require Logger
@doc """
Get the list of `videos`.
## Options
* `query`: Map of parameters to filter the query
- q: query string in title, additional_title, original_title (case insensitive)
- qid: filter with the video identifier
- page: page index
- per_page: number of items per page
- etc.
## Response example
```elixir
%{
videos: [
%{
"id": "978f7146-41e3-11e6-8153-000d3a23d482",
"created_at": "2015-09-16T10:55:12.200+02:00",
"updated_at": "2015-09-16T10:55:12.200+02:00",
"created_by": nil,
"created_via": "import-plurimedia-epg",
"title": "Amour, gloire et beauté",
"additional_title": "La vengeance de Samantha",
"category": %{
"id": "series-fictions",
"label": "séries & fictions"
},
...
"images": [%{image}, %{image}, ...],
"licensing": "svod",
"embeddable": true,
...
"platforms": %{
"ftv": %{ ... },
"bouygues": %{ ... },
"orange": %{ ... },
...
}
"groups": [
%{
"id": "ea2bed61-47e0-4116-bf8c-33c375fd9030",
"label": "Amour, gloire et beauté - Saison 13",
...
"images": [%{image}, %{image}, ...],
},
...
]
},
...
],
size: 10,
offset: 0,
total: 16238
}
```
"""
def videos(query \\ %{}) do
page =
Map.get(query, "page", 1)
|> force_integer
page_size =
Map.get(query, "per_page", 20)
|> force_integer
query =
query
|> format_query
response = ExVideoFactory.Client.get("videos", query: query)
case response do
%HTTPotion.Response{} ->
total = get_total_number_of_elements(response)
list = response.body
%{
videos: list,
size: length(list),
offset: (page - 1) * page_size + 1,
total: total
}
msg ->
Logger.warn("#{msg}")
%{
videos: [],
size: 0,
offset: 0,
total: 0,
}
end
end
@doc """
Get the list of `regions`.
## Response example
```elixir
%{
regions: [
%{
"id": "saint-pierre-et-miquelon",
"label": "Saint-Pierre et Miquelon",
"code": "SPM",
"time_zone": "America/Miquelon"
},
...
],
size: 10,
total: 12
}
```
"""
def regions do
response = ExVideoFactory.Client.get("regions")
list = response.body
total = get_total_number_of_elements(response)
%{
regions: list,
size: length(list),
total: total
}
end
@doc """
Get the list of `types`.
## Response example
```elixir
%{
types: [
%{
"id": "bande-annonce",
"label": "Bande-Annonce"
},
...
],
size: 10,
total: 24
}
```
"""
def types do
response = ExVideoFactory.Client.get("types")
list = response.body
total = get_total_number_of_elements(response)
%{
types: list,
size: length(list),
total: total
}
end
@doc """
Get the list of `channels`.
## Response example
```elixir
%{
"channels": [
%{
"id": "saint-pierre-et-miquelon-1ere",
"label": "Saint-Pierre et Miquelon 1ère",
"region": %{
"id": "saint-pierre-et-miquelon",
"label": "Saint-Pierre et Miquelon"
"code": "SPM",
"time_zone": "America/Miquelon"
},
"tags": ["outremer"]
},
...
],
"size": 10,
"total": 30
}
```
"""
def channels do
response = ExVideoFactory.Client.get("channels")
list = response.body
total = get_total_number_of_elements(response)
%{
channels: list,
size: length(list),
total: total
}
end
defp get_total_number_of_elements(%HTTPotion.Response{headers: headers}) do
headers['X-Total-Count']
end
defp get_total_number_of_elements(_) do
0
end
defp force_integer(param) when is_bitstring(param) do
param
|> String.to_integer()
end
defp force_integer(param) do
param
end
@doc false
def format_query(query) do
query
|> Enum.map(fn {key, value} ->
format_field(key, value)
end)
|> Map.new()
end
defp format_field(key, value) do
format_field(key, String.split(key, "_"), value)
end
defp format_field(_, [prefix, "after"], value) do
{prefix <> "_at[gte]", format_iso8601(value)}
end
defp format_field(_, [prefix, "before"], value) do
{prefix <> "_at[lte]", format_iso8601(value)}
end
defp format_field("channels", _, value) do
{"channel.id", Enum.join(value, ",")}
end
defp format_field(key, _, value) do
{key, value}
end
defp format_iso8601(date) do
char = String.at(date, 19)
case char do
" " ->
String.replace(date, ~r/\s/, "+")
nil ->
raise ArgumentError, message: "Unsupported date format: " <> date
_ ->
date
end
end
@doc """
Get the list of files information based on `Video` identifier.
## Response example
```elixir
[
{
"created_at": "2018-05-03T18:29:57+02:00",
"updated_at": "2018-05-03T18:29:57+02:00",
"id": "c465b024-75a1-479d-9195-effe90da9cbd",
"format": {
"id": "video-mp4",
"label": "video/mp4",
"type": "video",
"mime_type": "video/mp4"
},
"storage": "akamai-replay-prod",
"path": "/streaming-adaptatif_france-dom-tom/2018/S18/J4/",
"filename": "176668575-5aeb383753763-standard5.mp4",
"md5_checksum": null,
"filesize_bytes": 82099370,
"external_ids": {
"video_id": "32a2748d-9aa3-430b-9287-fc840f55b012",
"legacy_id": "176668575",
"group_id": null,
"job_id": "2695577",
"remote_id": null
},
"tags": [],
"created_via": "factory",
"version": "1525364791000000",
"bitrate_kbps": 1471,
"video_tracks": [
{
"codec_rfc6381": "avc1.4d001f",
"bitrate_kbps": 1390,
"width": 1024,
"height": 576,
"frame_rate_fps": 25
}
],
"audio_tracks": [
{
"codec_rfc6381": "mp4a.40.2",
"bitrate_kbps": 81,
"sample_rate_hz": 48000,
"lang": "fra"
}
],
"text_tracks": [],
"url": "https://replayftv-vh.akamaihd.net/z/streaming-adaptatif_france-dom-tom/2018/S18/J4/176668575-5aeb383753763-standard5.mp4"
},
...
]
```
"""
def get_files_for_video_id(id) do
query = %{"external_ids.video_id": id, per_page: 1000}
ExVideoFactory.Client.get("files", query: query).body
end
@doc """
Get the list of files on FTP server based on `Video` identifier.
## Response example
```elixir
[
"/ftp/file/path/quality_1.mp4",
"/ftp/file/path/quality_2.mp4",
"/ftp/file/path/quality_3.mp4",
"/ftp/file/path/quality_4.mp4",
"/ftp/file/path/quality_5.mp4",
]
```
"""
def get_ftp_paths_for_video_id(id) do
query = %{"external_ids.video_id": id, per_page: 1000}
ExVideoFactory.Client.get("files", query: query).body
|> get_files
end
@doc """
Get the list of files on FTP server based on `Video` diffusion identifier.
## Response example
```elixir
[
%{
format: "hds_akamai",
urls: []
},
%{
format: "m3u8-download",
urls: [
"/ftp/file/path/quality_1.mp4",
"/ftp/file/path/quality_2.mp4",
"/ftp/file/path/quality_3.mp4",
"/ftp/file/path/quality_4.mp4"
]
},
%{
format: "hls_v5_os",
urls: [
"/ftp/file/path/quality_1.mp4",
"/ftp/file/path/quality_2.mp4",
"/ftp/file/path/quality_3.mp4",
"/ftp/file/path/quality_4.mp4",
"/ftp/file/path/quality_5.mp4"
]
}
]
```
"""
def get_ftp_paths_for_id_diffusion(id_diffusion) do
query = [idDiffusion: id_diffusion]
ExVideoFactory.LegacyClient.get("getInfosOeuvre/v2/", query: query).body
|> get_legacy_files
end
@doc """
Get the list of HTTP URLs for TTML contents based on `Video` identifier.
## Response example
```elixir
[
"https://sample-server.com/some/path/caption.ttml",
]
```
"""
def get_http_url_for_ttml(id) do
query = %{
"external_ids.video_id": id,
per_page: 1000,
"format.id": "caption-ttml"
}
ExVideoFactory.Client.get("files", query: query).body
|> get_urls([])
end
@doc false
def get_files(content) do
content
|> format_files([])
end
@doc false
def get_legacy_files(content) do
content
|> Map.get("videos")
|> format_legacy_files([])
end
defp format_files([], list), do: list
defp format_files([item | items], list) do
list =
case format_file(item) do
nil -> list
filename -> List.insert_at(list, -1, filename)
end
format_files(items, list)
end
defp format_legacy_files([], list), do: list
defp format_legacy_files([item | items], list) do
list =
case item do
%{"format" => _format, "url" => nil} ->
list
%{"format" => format, "url" => url} ->
item = %{
format: format,
urls: format_url(url)
}
List.insert_at(list, -1, item)
end
format_legacy_files(items, list)
end
defp format_url("http://replayftv-vh.akamaihd.net/i/" <> url) do
list = String.split(url, ",")
[base_root, _extension] = Enum.filter(list, fn item -> !is_standard(item) end)
qualities = Enum.filter(list, fn item -> is_standard(item) end)
for quality <- qualities do
"/343079/http/#{base_root}#{quality}.mp4"
end
end
defp format_url(_url) do
[]
end
defp is_standard("standard" <> _id), do: true
defp is_standard(_something), do: false
defp format_file(%{"format" => %{"id" => id, "mime_type" => mime_type}} = item) do
case {id, mime_type} do
{"video-mp4", "video/mp4"} ->
case Map.get(item, "storage") do
"akamai-replay-prod" ->
path = Map.get(item, "path")
filename = Map.get(item, "filename")
"/343079/http" <> path <> filename
_ ->
nil
end
{"manifest-ism", "application/xml"} ->
case Map.get(item, "storage") do
"amazon-replay-prod" ->
path = Map.get(item, "path")
filename = Map.get(item, "filename")
path <> filename
_ ->
nil
end
_ ->
nil
end
end
defp format_file(_item) do
nil
end
@doc false
def get_urls([], result), do: result
def get_urls([item | items], result) do
result =
case Map.get(item, "url", nil) do
nil -> result
url -> List.insert_at(result, -1, url)
end
get_urls(items, result)
end
end