mirror of
https://github.com/sudoxnym/fin-assistant.git
synced 2026-04-14 11:37:38 +00:00
upcoming and yamc contd
This commit is contained in:
parent
78fb20fd66
commit
b99157c12a
9 changed files with 255 additions and 29 deletions
|
|
@ -14,6 +14,7 @@ Jellyfin integration for Home Assistant
|
|||
|
||||
- 1 media_player entity per device
|
||||
- 1 sensor per server
|
||||
- Supports the "upcoming-media-card" custom card
|
||||
|
||||
### Media Browser
|
||||
|
||||
|
|
|
|||
199
__init__.py
199
__init__.py
|
|
@ -1,4 +1,5 @@
|
|||
"""The jellyfin component."""
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
import re
|
||||
|
|
@ -19,6 +20,7 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ( # pylint: disable=import-error
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_ID,
|
||||
CONF_URL,
|
||||
CONF_USERNAME,
|
||||
CONF_PASSWORD,
|
||||
|
|
@ -38,10 +40,17 @@ from .const import (
|
|||
CLIENT_VERSION,
|
||||
SIGNAL_STATE_UPDATED,
|
||||
SERVICE_SCAN,
|
||||
SERVICE_BROWSE,
|
||||
SERVICE_DELETE,
|
||||
SERVICE_YAMC_SETPAGE,
|
||||
ATTR_PAGE,
|
||||
STATE_OFF,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_PLAYING,
|
||||
CONF_GENERATE_UPCOMING,
|
||||
CONF_GENERATE_YAMC,
|
||||
YAMC_PAGE_SIZE,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
|
@ -52,11 +61,39 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)
|
|||
|
||||
PATH_REGEX = re.compile("^(https?://)?([^/:]+)(:[0-9]+)?(/.*)?$")
|
||||
|
||||
SCAN_SERVICE_SCHEMA = vol.Schema(
|
||||
SERVICE_SCHEMA = vol.Schema({
|
||||
})
|
||||
|
||||
SCAN_SERVICE_SCHEMA = SERVICE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
}
|
||||
)
|
||||
YAMC_SETPAGE_SERVICE_SCHEMA = SERVICE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_PAGE): vol.All(vol.Coerce(int))
|
||||
}
|
||||
)
|
||||
DELETE_SERVICE_SCHEMA = SERVICE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_ID): cv.string
|
||||
}
|
||||
)
|
||||
BROWSE_SERVICE_SCHEMA = SERVICE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_ID): cv.string
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_TO_METHOD = {
|
||||
SERVICE_SCAN: {'method': 'async_trigger_scan', 'schema': SCAN_SERVICE_SCHEMA},
|
||||
SERVICE_BROWSE: {'method': 'async_browse_item', 'schema': BROWSE_SERVICE_SCHEMA},
|
||||
SERVICE_DELETE: {'method': 'async_delete_item', 'schema': DELETE_SERVICE_SCHEMA},
|
||||
SERVICE_YAMC_SETPAGE: {'method': 'async_yamc_setpage', 'schema': YAMC_SETPAGE_SERVICE_SCHEMA},
|
||||
}
|
||||
|
||||
def autolog(message):
|
||||
"Automatically log the current function details."
|
||||
|
|
@ -108,19 +145,25 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
|
|||
_LOGGER.error("Cannot connect to Jellyfin server.")
|
||||
raise
|
||||
|
||||
async def service_trigger_scan(service):
|
||||
async def async_service_handler(service):
|
||||
"""Map services to methods"""
|
||||
method = SERVICE_TO_METHOD.get(service.service)
|
||||
params = {key: value for key, value in service.data.items() if key != "entity_id"}
|
||||
|
||||
entity_id = service.data.get(ATTR_ENTITY_ID)
|
||||
|
||||
for sensor in hass.data[DOMAIN][config.get(CONF_URL)]["sensor"]["entities"]:
|
||||
if sensor.entity_id == entity_id:
|
||||
await sensor.async_trigger_scan()
|
||||
await getattr(sensor, method['method'])(**params)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_SCAN,
|
||||
service_trigger_scan,
|
||||
schema=SCAN_SERVICE_SCHEMA,
|
||||
)
|
||||
for media_player in hass.data[DOMAIN][config.get(CONF_URL)]["media_player"]["entities"]:
|
||||
if media_player.entity_id == entity_id:
|
||||
await getattr(media_player, method['method'])(**params)
|
||||
|
||||
for my_service in SERVICE_TO_METHOD:
|
||||
schema = SERVICE_TO_METHOD[my_service].get('schema', SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, my_service, async_service_handler, schema=schema)
|
||||
|
||||
for component in PLATFORMS:
|
||||
hass.data[DOMAIN][config.get(CONF_URL)][component] = {}
|
||||
|
|
@ -143,6 +186,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
|
|||
|
||||
async def _update_listener(hass, config_entry):
|
||||
"""Update listener."""
|
||||
_LOGGER.debug("reload triggered")
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
|
||||
|
|
@ -403,6 +447,9 @@ class JellyfinDevice(object):
|
|||
async def play_media(self, media_id):
|
||||
await self.jf_manager.play_media(self.session_id, media_id)
|
||||
|
||||
async def browse_item(self, media_id):
|
||||
await self.jf_manager.view_media(self.session_id, media_id)
|
||||
|
||||
class JellyfinClientManager(object):
|
||||
def __init__(self, hass: HomeAssistant, config_entry):
|
||||
self.hass = hass
|
||||
|
|
@ -414,6 +461,8 @@ class JellyfinClientManager(object):
|
|||
self.host = config_entry[CONF_URL]
|
||||
self._info = None
|
||||
self._data = None
|
||||
self._yamc = None
|
||||
self._yamc_cur_page = 1
|
||||
|
||||
self.config_entry = config_entry
|
||||
self.server_url = ""
|
||||
|
|
@ -582,12 +631,27 @@ class JellyfinClientManager(object):
|
|||
|
||||
@util.Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
async def update_data(self):
|
||||
self._data = await self.hass.async_add_executor_job(self.jf_client.jellyfin.shows, "/NextUp", {
|
||||
'Limit': 10,
|
||||
'UserId': "{UserId}",
|
||||
"fields": "DateCreated,Studios,Genres"
|
||||
})
|
||||
_LOGGER.debug("update_data: %s", str(self._data))
|
||||
if self.config_entry[CONF_GENERATE_UPCOMING]:
|
||||
self._data = await self.hass.async_add_executor_job(self.jf_client.jellyfin.shows, "/NextUp", {
|
||||
'Limit': YAMC_PAGE_SIZE,
|
||||
'UserId': "{UserId}",
|
||||
"fields": "DateCreated,Studios,Genres"
|
||||
})
|
||||
#_LOGGER.debug("update data: %s", str(self._data))
|
||||
|
||||
if self.config_entry[CONF_GENERATE_YAMC]:
|
||||
self._yamc = await self.hass.async_add_executor_job(self.jf_client.jellyfin.items, "", "GET", {
|
||||
'startIndex': (self._yamc_cur_page - 1) * YAMC_PAGE_SIZE,
|
||||
'limit': YAMC_PAGE_SIZE,
|
||||
'userId': "{UserId}",
|
||||
'includeItemTypes': "Movie",
|
||||
'sortBy': 'DateCreated',
|
||||
'sortOrder': 'Descending',
|
||||
'recursive': 'true',
|
||||
"fields": "DateCreated,Studios,Genres,Taglines,ProviderIds",
|
||||
'collapseBoxSetItems': 'false',
|
||||
})
|
||||
_LOGGER.debug("update yamc: %s", str(self._yamc))
|
||||
|
||||
def update_device_list(self):
|
||||
""" Update device list. """
|
||||
|
|
@ -705,7 +769,7 @@ class JellyfinClientManager(object):
|
|||
@property
|
||||
def data(self):
|
||||
"""Upcoming card data"""
|
||||
if self.is_stopping:
|
||||
if self.config_entry[CONF_GENERATE_UPCOMING] == False or self.is_stopping:
|
||||
return None
|
||||
|
||||
data = []
|
||||
|
|
@ -734,13 +798,105 @@ class JellyfinClientManager(object):
|
|||
"poster": self.get_artwork_url(item["Id"]),
|
||||
"fanart": self.get_artwork_url(item["Id"], "Backdrop"),
|
||||
"genres": ",".join(item["Genres"]),
|
||||
"rating": None,
|
||||
"stream_url": None,
|
||||
"trakt_url": None,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def yamc(self):
|
||||
"""Upcoming card data"""
|
||||
if self.config_entry[CONF_GENERATE_YAMC] == False or self.is_stopping:
|
||||
return None
|
||||
|
||||
data = []
|
||||
data.append({
|
||||
'title_default': '$title',
|
||||
'line1_default': '$tagline',
|
||||
'line2_default': '$empty',
|
||||
'line3_default': '$release - $genres',
|
||||
'line4_default': '$runtime - $rating - $info',
|
||||
'line5_default': '$date',
|
||||
'text_link_default': '$trakt_url',
|
||||
'link_default': '$stream_url',
|
||||
})
|
||||
|
||||
if self._yamc is None or "Items" not in self._yamc:
|
||||
return data
|
||||
|
||||
for item in self._yamc["Items"]:
|
||||
imdbid = None
|
||||
if item["Type"] == "Movie":
|
||||
if "ProviderIds" in item and "Imdb" in item["ProviderIds"]:
|
||||
imdbid = item["ProviderIds"]["Imdb"]
|
||||
|
||||
data.append({
|
||||
"id": item["Id"],
|
||||
"type": item["Type"],
|
||||
"title": item["Name"],
|
||||
"tagline": item["Taglines"][0] if "Taglines" in item and len(item["Taglines"]) > 0 else "",
|
||||
"flag": False,
|
||||
"airdate": item["DateCreated"],
|
||||
#"number": f'S{item["ParentIndexNumber"]}E{item["IndexNumber"]}',
|
||||
"runtime": int(item["RunTimeTicks"] / 10000000 / 60) if "RunTimeTicks" in item else None,
|
||||
"studio": ",".join(o["Name"] for o in item["Studios"]),
|
||||
"release": dt.parse(item["PremiereDate"]).__format__("%Y") if "PremiereDate" in item else None,
|
||||
"poster": self.get_artwork_url(item["Id"]),
|
||||
"fanart": self.get_artwork_url(item["Id"], "Backdrop"),
|
||||
"genres": ",".join(item["Genres"]),
|
||||
"progress": 0,
|
||||
"rating": None,
|
||||
"stream_url": None,
|
||||
'trakt_url': f"https://trakt.tv/search/imdb/{imdbid}?id_type=movie" if imdbid else "",
|
||||
})
|
||||
elif item["Type"] == "Episode":
|
||||
if "ProviderIds" in item and "Imdb" in item["ProviderIds"]:
|
||||
imdbid = item["ProviderIds"]["Imdb"]
|
||||
|
||||
data.append({
|
||||
"id": item["Id"],
|
||||
"type": item["Type"],
|
||||
"title": item["SeriesName"] if "SeriesName" in item else item["Name"],
|
||||
"episode": item["Name"],
|
||||
"tagline": item["Taglines"][0] if "Taglines" in item else "",
|
||||
"flag": False,
|
||||
"airdate": item["DateCreated"],
|
||||
"number": f'S{item["ParentIndexNumber"]}E{item["IndexNumber"]}',
|
||||
"runtime": int(item["RunTimeTicks"] / 10000000 / 60) if "RunTimeTicks" in item else None,
|
||||
"studio": ",".join(o["Name"] for o in item["Studios"]),
|
||||
"release": dt.parse(item["PremiereDate"]).__format__("%d/%m/%Y") if "PremiereDate" in item else None,
|
||||
"poster": self.get_artwork_url(item["Id"]),
|
||||
"fanart": self.get_artwork_url(item["Id"], "Backdrop"),
|
||||
"genres": ",".join(item["Genres"]),
|
||||
"progress": 0,
|
||||
"rating": None,
|
||||
"stream_url": None,
|
||||
'trakt_url': f"https://trakt.tv/search/imdb/{imdbid}?id_type=movie" if imdbid else "",
|
||||
})
|
||||
|
||||
attrs = {}
|
||||
attrs["last_search"] = None
|
||||
attrs["playlists"] = json.dumps([])
|
||||
attrs['total_items'] = min(50, self._yamc["TotalRecordCount"])
|
||||
attrs["page"] = self._yamc_cur_page
|
||||
attrs["page_size"] = YAMC_PAGE_SIZE
|
||||
attrs['data'] = json.dumps(data)
|
||||
|
||||
return attrs
|
||||
|
||||
async def trigger_scan(self):
|
||||
await self.hass.async_add_executor_job(self.jf_client.jellyfin._post, "Library/Refresh")
|
||||
|
||||
async def delete_item(self, id):
|
||||
await self.hass.async_add_executor_job(self.jf_client.jellyfin.items, f"/{id}", "DELETE")
|
||||
await self.update_data(no_throttle=True)
|
||||
|
||||
async def yamc_set_page(self, page):
|
||||
self._yamc_cur_page = page
|
||||
await self.update_data(no_throttle=True)
|
||||
|
||||
def get_server_url(self) -> str:
|
||||
return self.jf_client.config.data["auth.server"]
|
||||
|
||||
|
|
@ -765,6 +921,17 @@ class JellyfinClientManager(object):
|
|||
}
|
||||
await self.hass.async_add_executor_job(self.jf_client.jellyfin.post_session, session_id, "Playing", params)
|
||||
|
||||
async def view_media(self, session_id, media_id):
|
||||
item = await self.hass.async_add_executor_job(self.jf_client.jellyfin.get_item, media_id)
|
||||
_LOGGER.debug(f'view_media: {str(item)}')
|
||||
|
||||
params = {
|
||||
"itemId": media_id,
|
||||
"itemType": item["Type"],
|
||||
"itemName": item["Name"]
|
||||
}
|
||||
await self.hass.async_add_executor_job(self.jf_client.jellyfin.post_session, session_id, "Viewing", params)
|
||||
|
||||
async def get_artwork(self, media_id, type="Primary") -> Tuple[Optional[str], Optional[str]]:
|
||||
query = {
|
||||
"format": "PNG",
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ from .const import (
|
|||
DOMAIN,
|
||||
DEFAULT_SSL,
|
||||
DEFAULT_VERIFY_SSL,
|
||||
DEFAULT_PORT,
|
||||
CONN_TIMEOUT,
|
||||
CONF_GENERATE_UPCOMING,
|
||||
CONF_GENERATE_YAMC,
|
||||
)
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -63,6 +63,8 @@ class JellyfinFlowHandler(config_entries.ConfigFlow):
|
|||
vol.Required(CONF_USERNAME): str,
|
||||
vol.Required(CONF_PASSWORD): str,
|
||||
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): bool,
|
||||
vol.Optional(CONF_GENERATE_UPCOMING, default=False): bool,
|
||||
vol.Optional(CONF_GENERATE_YAMC, default=False): bool,
|
||||
}
|
||||
|
||||
if user_input is not None:
|
||||
|
|
@ -70,6 +72,8 @@ class JellyfinFlowHandler(config_entries.ConfigFlow):
|
|||
self._username = user_input[CONF_USERNAME]
|
||||
self._password = user_input[CONF_PASSWORD]
|
||||
self._verify_ssl = user_input[CONF_VERIFY_SSL]
|
||||
self._generate_upcoming = user_input[CONF_GENERATE_UPCOMING]
|
||||
self._generate_yamc = user_input[CONF_GENERATE_YAMC]
|
||||
|
||||
try:
|
||||
await self.async_set_unique_id(DOMAIN)
|
||||
|
|
@ -83,6 +87,8 @@ class JellyfinFlowHandler(config_entries.ConfigFlow):
|
|||
CONF_PASSWORD: self._password,
|
||||
CONF_VERIFY_SSL: self._verify_ssl,
|
||||
CONF_CLIENT_ID: str(uuid.uuid4()),
|
||||
CONF_GENERATE_UPCOMING: self._generate_upcoming,
|
||||
CONF_GENERATE_YAMC: self._generate_yamc,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -115,6 +121,8 @@ class JellyfinOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
self._username = config_entry.data[CONF_USERNAME] if CONF_USERNAME in config_entry.data else None
|
||||
self._password = config_entry.data[CONF_PASSWORD] if CONF_PASSWORD in config_entry.data else None
|
||||
self._verify_ssl = config_entry.data[CONF_VERIFY_SSL] if CONF_VERIFY_SSL in config_entry.options else DEFAULT_VERIFY_SSL
|
||||
self._generate_upcoming = config_entry.data[CONF_GENERATE_UPCOMING] if CONF_GENERATE_UPCOMING in config_entry.options else False
|
||||
self._generate_yamc = config_entry.data[CONF_GENERATE_YAMC] if CONF_GENERATE_YAMC in config_entry.options else False
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Manage the options."""
|
||||
|
|
@ -128,12 +136,16 @@ class JellyfinOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
self._username = user_input[CONF_USERNAME]
|
||||
self._password = user_input[CONF_PASSWORD]
|
||||
self._verify_ssl = user_input[CONF_VERIFY_SSL]
|
||||
self._generate_upcoming = user_input[CONF_GENERATE_UPCOMING]
|
||||
self._generate_yamc = user_input[CONF_GENERATE_YAMC]
|
||||
|
||||
data_schema = {
|
||||
vol.Required(CONF_URL, default=self._url): str,
|
||||
vol.Required(CONF_USERNAME, default=self._username): str,
|
||||
vol.Required(CONF_PASSWORD, default=self._password): str,
|
||||
vol.Optional(CONF_VERIFY_SSL, default=self._verify_ssl): bool,
|
||||
vol.Optional(CONF_GENERATE_UPCOMING, default=self._generate_upcoming): bool,
|
||||
vol.Optional(CONF_GENERATE_YAMC, default=self._generate_yamc): bool,
|
||||
}
|
||||
|
||||
if user_input is not None:
|
||||
|
|
@ -145,6 +157,8 @@ class JellyfinOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
CONF_USERNAME: self._username,
|
||||
CONF_PASSWORD: self._password,
|
||||
CONF_VERIFY_SSL: self._verify_ssl,
|
||||
CONF_GENERATE_UPCOMING: self._generate_upcoming,
|
||||
CONF_GENERATE_YAMC: self._generate_yamc,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
13
const.py
13
const.py
|
|
@ -2,7 +2,13 @@
|
|||
|
||||
DOMAIN = "jellyfin"
|
||||
SIGNAL_STATE_UPDATED = "{}.updated".format(DOMAIN)
|
||||
|
||||
SERVICE_SCAN = "trigger_scan"
|
||||
SERVICE_YAMC_SETPAGE = "yamc_setpage"
|
||||
SERVICE_BROWSE = "browse"
|
||||
SERVICE_DELETE = "delete"
|
||||
|
||||
ATTR_PAGE = 'page'
|
||||
|
||||
USER_APP_NAME = "Home Assistant"
|
||||
CLIENT_VERSION = "1.0"
|
||||
|
|
@ -16,4 +22,9 @@ CONN_TIMEOUT = 5.0
|
|||
STATE_PLAYING = 'Playing'
|
||||
STATE_PAUSED = 'Paused'
|
||||
STATE_IDLE = 'Idle'
|
||||
STATE_OFF = 'Off'
|
||||
STATE_OFF = 'Off'
|
||||
|
||||
CONF_GENERATE_UPCOMING = "generate_upcoming"
|
||||
CONF_GENERATE_YAMC = "generate_yamc"
|
||||
|
||||
YAMC_PAGE_SIZE=7
|
||||
|
|
@ -336,3 +336,7 @@ class JellyfinMediaPlayer(MediaPlayerEntity):
|
|||
async def async_play_media(self, media_type: str, media_id: str, **kwargs) -> None:
|
||||
_LOGGER.debug("Play media requested: %s / %s", media_type, media_id)
|
||||
await self.device.play_media(media_id)
|
||||
|
||||
async def async_browse_item(self, id):
|
||||
_LOGGER.debug(f"async_browse_item triggered {id}")
|
||||
await self.device.browse_item(id)
|
||||
|
|
|
|||
21
sensor.py
21
sensor.py
|
|
@ -85,13 +85,30 @@ class JellyfinSensor(Entity):
|
|||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
return {
|
||||
extra_attr = {
|
||||
"os": self.jelly_cm.info["OperatingSystem"],
|
||||
"update_available": self.jelly_cm.info["HasUpdateAvailable"],
|
||||
"version": self.jelly_cm.info["Version"],
|
||||
"data": self.jelly_cm.data,
|
||||
}
|
||||
if self.jelly_cm.data:
|
||||
extra_attr["data"] = self.jelly_cm.data
|
||||
if self.jelly_cm.yamc:
|
||||
extra_attr["yamc"] = self.jelly_cm.yamc
|
||||
|
||||
return extra_attr
|
||||
|
||||
async def async_trigger_scan(self):
|
||||
_LOGGER.info("Library scan triggered")
|
||||
await self.jelly_cm.trigger_scan()
|
||||
|
||||
async def async_delete_item(self, id):
|
||||
_LOGGER.debug("async_delete_item triggered")
|
||||
await self.jelly_cm.delete_item(id)
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
async def async_yamc_setpage(self, page):
|
||||
_LOGGER.debug("YAMC setpage: %d", page)
|
||||
|
||||
await self.jelly_cm.yamc_set_page(page)
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
|
|
|
|||
12
strings.json
12
strings.json
|
|
@ -4,13 +4,15 @@
|
|||
"flow_title": "Jellyfin Configuration",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Luci Config",
|
||||
"description": "Configure the connection details.",
|
||||
"title": "Jellyfin Config",
|
||||
"description": "Configure the integration.",
|
||||
"data": {
|
||||
"url": "[%key:common::config_flow::data::url%]",
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]",
|
||||
"generate_upcoming": "Generate Upcoming card data",
|
||||
"generate_yamc": "Generate YAMC card data"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -33,7 +35,9 @@
|
|||
"url": "[%key:common::config_flow::data::url%]",
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
|
||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]",
|
||||
"generate_upcoming": "Generate Upcoming card data",
|
||||
"generate_yamc": "Generate YAMC card data"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
"url": "Host URL",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"verify_ssl": "Verify SSL host"
|
||||
"verify_ssl": "Verify SSL host",
|
||||
"generate_upcoming": "Generate Upcoming card data",
|
||||
"generate_yamc": "Generate YAMC card data"
|
||||
},
|
||||
"description": "Configure the connection details.",
|
||||
"title": "Jellyfin"
|
||||
|
|
@ -38,7 +40,9 @@
|
|||
"url": "Host URL",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"verify_ssl": "Verify SSL host"
|
||||
"verify_ssl": "Verify SSL host",
|
||||
"generate_upcoming": "Generate Upcoming card data",
|
||||
"generate_yamc": "Generate YAMC card data"
|
||||
},
|
||||
"description": "Configure the connection details.",
|
||||
"title": "Jellyfin"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
"url": "URL Serveur",
|
||||
"username": "Utilisateur",
|
||||
"password": "Mot de passe",
|
||||
"verify_ssl": "Vérification SSL"
|
||||
"verify_ssl": "Vérification SSL",
|
||||
"generate_upcoming": "Générer les données pour la carte Upcoming",
|
||||
"generate_yamc": "Générer les données pour la carte YAMC"
|
||||
},
|
||||
"description": "Configuration des paramètres de connexion.",
|
||||
"title": "Jellyfin"
|
||||
|
|
@ -38,7 +40,9 @@
|
|||
"url": "URL Serveur",
|
||||
"username": "Utilisateur",
|
||||
"password": "Mot de passe",
|
||||
"verify_ssl": "Vérification SSL"
|
||||
"verify_ssl": "Vérification SSL",
|
||||
"generate_upcoming": "Générer les données pour la carte Upcoming",
|
||||
"generate_yamc": "Générer les données pour la carte YAMC"
|
||||
},
|
||||
"description": "Configuration des paramètres de connexion.",
|
||||
"title": "Jellyfin"
|
||||
|
|
|
|||
Loading…
Reference in a new issue