From f0e91b7538cc2a82be51f228619232cf7e477879 Mon Sep 17 00:00:00 2001 From: herby2212 <12448284+herby2212@users.noreply.github.com> Date: Tue, 3 Jan 2023 06:15:00 +0100 Subject: [PATCH 1/8] initial commit --- .../default/current_activity_instance.html | 21 ++++++++++--- data/interfaces/default/info.html | 31 ++++++++++++++----- .../default/info_children_list.html | 5 +-- data/interfaces/default/js/script.js | 4 +++ .../default/js/tables/history_table.js | 2 ++ .../default/js/tables/history_table_modal.js | 2 ++ .../default/js/tables/media_info_table.js | 4 ++- data/interfaces/default/js/tables/users.js | 2 ++ .../default/library_recently_added.html | 7 ++++- data/interfaces/default/recently_added.html | 8 ++++- .../default/user_recently_watched.html | 10 +++++- .../newsletters/recently_added.html | 13 +++++--- plexpy/common.py | 1 + plexpy/helpers.py | 3 ++ plexpy/libraries.py | 2 ++ plexpy/newsletters.py | 2 ++ plexpy/notification_handler.py | 7 +++-- plexpy/pmsconnect.py | 1 + plexpy/webserve.py | 1 + 19 files changed, 101 insertions(+), 25 deletions(-) diff --git a/data/interfaces/default/current_activity_instance.html b/data/interfaces/default/current_activity_instance.html index b48a70f3..95056968 100644 --- a/data/interfaces/default/current_activity_instance.html +++ b/data/interfaces/default/current_activity_instance.html @@ -10,14 +10,15 @@ Variable names: data {dict} data :: Usable parameters == Global keys == -session_key Returns a unique session id for the active stream +session_key Returns a unique session id for the active stream. rating_key Returns the unique identifier for the media item. media_index Returns the index of the media item. parent_media_index Returns the index of the media item's parent. media_type Returns the type of session. Either 'track', 'episode' or 'movie'. thumb Returns the location of the item's thumbnail. Use with pms_image_proxy. bif_thumb Returns the location of the item's bif thumbnail. Use with pms_image_proxy. -art Returns the location of the item's artwork +art Returns the location of the item's artwork. +originally_available_at Returns the air date of the item. progress_percent Returns the current progress of the item. 0 to 100. user Returns the name of the user owning the session. user_id Returns the Plex user id if available. @@ -62,7 +63,7 @@ DOCUMENTATION :: END % if session is not None: <% from collections import defaultdict - from plexpy.helpers import cast_to_int, get_percent, page, short_season + from plexpy.helpers import cast_to_int, get_percent, page, short_season, format_date_based_show from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES import plexpy %> @@ -76,6 +77,12 @@ DOCUMENTATION :: END user_href = page('user', data['user_id']) if data['user_id'] else '#' season = short_season(data['parent_title']) %> +% if not data['media_index']: +<% + data['originally_available_at'] = format_date_based_show(data['originally_available_at']) +%> +% endif +
@@ -499,8 +506,12 @@ DOCUMENTATION :: END % if data['media_type'] == 'movie': ${data['year']} % elif data['media_type'] == 'episode': - ${season} - · E${data['media_index']} + % if data['media_index']: + ${season} + · E${data['media_index']} + % else: + E${data['originally_available_at']} + % endif % elif data['media_type'] == 'track': ${data['parent_title']} % elif data['media_type'] == 'photo': diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index 6d8b3aaf..8a81b36c 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -41,7 +41,7 @@ DOCUMENTATION :: END from plexpy import notifiers from plexpy.common import MEDIA_TYPE_HEADERS, MEDIA_FLAGS_AUDIO, MEDIA_FLAGS_VIDEO - from plexpy.helpers import page, get_percent, cast_to_int, short_season + from plexpy.helpers import page, get_percent, cast_to_int, short_season, format_date_based_show # Get audio codec file def af(codec): @@ -81,9 +81,14 @@ DOCUMENTATION :: END <% data = defaultdict(lambda: None, **metadata) media_info = defaultdict(lambda: None, **(data['media_info'][0] if data['media_info'] else {})) + episode = '' season = '' if data['media_type'] == 'episode': season = short_season(data['parent_title']) + if data['media_index']: + episode = data['media_index'] + else: + episode = format_date_based_show(data['originally_available_at']) elif data['media_type'] == 'season': season = short_season(data['title']) %> @@ -138,7 +143,7 @@ DOCUMENTATION :: END
  • ${data['parent_title']}
  • -
  • Episode ${data['media_index']} - ${data['title']}
  • +
  • Episode ${episode} - ${data['title']}
  • % elif data['media_type'] == 'artist':
  • ${data['library_name']}
  • @@ -249,10 +254,13 @@ DOCUMENTATION :: END % elif data['media_type'] == 'episode':

    ${data['grandparent_title']}

    ${data['title']}

    - % if data['media_index']: - - % endif + % if data['media_index']: + + % else: + + % endif % endif + % endif % elif data['media_type'] in ('movie', 'show', 'artist', 'collection', 'playlist', 'photo_album'):

     

    ${data['title']}

    % elif data['media_type'] == 'season': @@ -261,7 +269,11 @@ DOCUMENTATION :: END % elif data['media_type'] == 'episode':

    ${data['grandparent_title']}

    ${data['title']}

    - + % if data['media_index']: + + % else: + + % endif % elif data['media_type'] == 'album':

    ${data['parent_title']}

    ${data['title']}

    @@ -754,9 +766,14 @@ DOCUMENTATION :: END % if metadata: <% data = defaultdict(None, **metadata) + episode = '' season = '' if data['media_type'] == 'episode': season = short_season(data['parent_title']) + if data['media_index']: + episode = data['media_index'] + else: + episode = format_date_based_show(data['originally_available_at']) elif data['media_type'] == 'season': season = short_season(data['title']) %> @@ -800,7 +817,7 @@ DOCUMENTATION :: END % elif data['media_type'] == 'season': ${data['parent_title']}
    ${data['title']} % elif data['media_type'] == 'episode': - ${data['grandparent_title']}
    ${data['title']}
    ${season} · E${data['media_index']} + ${data['grandparent_title']}
    ${data['title']}
    ${season} · E${episode} % elif data['media_type'] == 'artist': ${data['title']} % elif data['media_type'] == 'album': diff --git a/data/interfaces/default/info_children_list.html b/data/interfaces/default/info_children_list.html index 14f85275..7908312a 100644 --- a/data/interfaces/default/info_children_list.html +++ b/data/interfaces/default/info_children_list.html @@ -19,6 +19,7 @@ data['children_list'] :: Usable paramaters == Global keys == rating_key Returns the unique identifier for the media item. media_index Returns the episode number. +originally_available_at Returns the air date of the item. title Returns the name of the episode. thumb Returns the location of the item's thumbnail. Use with pms_image_proxy. parent_thumb Returns the location of the item's parent thumbnail. Use with pms_image_proxy. @@ -28,7 +29,7 @@ DOCUMENTATION :: END % if data != None: <% - from plexpy.helpers import cast_to_int, page, short_season + from plexpy.helpers import cast_to_int, page, short_season, format_date_based_show %> % if data['children_count'] > 0:
    @@ -166,7 +167,7 @@ DOCUMENTATION :: END
    - Episode ${child['media_index'] or child['originally_available_at']} + Episode ${child['media_index'] or format_date_based_show(child['originally_available_at'])}
    diff --git a/data/interfaces/default/js/script.js b/data/interfaces/default/js/script.js index 2df5daeb..0de7d8b0 100644 --- a/data/interfaces/default/js/script.js +++ b/data/interfaces/default/js/script.js @@ -853,6 +853,10 @@ function short_season(title) { return title } +function format_date_based_show(date) { + return String(date).replaceAll('-', '\u00B7') +} + function loadAllBlurHash() { $('[data-blurhash]').each(function() { const elem = $(this); diff --git a/data/interfaces/default/js/tables/history_table.js b/data/interfaces/default/js/tables/history_table.js index deefa067..863eda90 100644 --- a/data/interfaces/default/js/tables/history_table.js +++ b/data/interfaces/default/js/tables/history_table.js @@ -179,9 +179,11 @@ history_table_options = { thumb_popover = '' + cellData + parent_info + ''; $(td).html(''); } else if (rowData['media_type'] === 'episode') { + rowData['originally_available_at'] = format_date_based_show(rowData['originally_available_at']); icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television'; icon_title = (rowData['live']) ? 'Live TV' : 'Episode'; if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (' + short_season(rowData['parent_title']) + ' · E' + rowData['media_index'] + ')'; } + else if (isNaN(parseInt(rowData['media_index'])) && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } media_type = ''; thumb_popover = '' + cellData + parent_info + ''; diff --git a/data/interfaces/default/js/tables/history_table_modal.js b/data/interfaces/default/js/tables/history_table_modal.js index 87ac4715..bdbcc525 100644 --- a/data/interfaces/default/js/tables/history_table_modal.js +++ b/data/interfaces/default/js/tables/history_table_modal.js @@ -112,9 +112,11 @@ history_table_modal_options = { thumb_popover = '' + cellData + parent_info + ''; $(td).html(''); } else if (rowData['media_type'] === 'episode') { + rowData['originally_available_at'] = format_date_based_show(rowData['originally_available_at']); icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television'; icon_title = (rowData['live']) ? 'Live TV' : 'Episode'; if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (' + short_season(rowData['parent_title']) + ' · E' + rowData['media_index'] + ')'; } + else if (isNaN(parseInt(rowData['media_index'])) && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } media_type = ''; thumb_popover = '' + cellData + parent_info + ''; diff --git a/data/interfaces/default/js/tables/media_info_table.js b/data/interfaces/default/js/tables/media_info_table.js index f4d80d53..8e26c9f8 100644 --- a/data/interfaces/default/js/tables/media_info_table.js +++ b/data/interfaces/default/js/tables/media_info_table.js @@ -94,7 +94,9 @@ media_info_table_options = { $(td).html(''); } else if (rowData['media_type'] === 'episode') { media_type = ''; - thumb_popover = 'E' + rowData['media_index'] + ' - ' + rowData['title'] + ''; + thumb_popover = (rowData['media_index']) ? + 'E' + rowData['media_index'] + ' - ' + rowData['title'] + '' + : 'E' + format_date_based_show(rowData['originally_available_at']) + ' - ' + rowData['title'] + ''; $(td).html(''); } else if (rowData['media_type'] === 'artist') { media_type = ''; diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index 524ee09a..9c38dd0b 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -211,7 +211,9 @@ users_list_table_options = { } else if (rowData['media_type'] === 'episode') { icon = (rowData['live']) ? 'fa-broadcast-tower' : 'fa-television'; icon_title = (rowData['live']) ? 'Live TV' : 'Episode'; + rowData['originally_available_at'] = format_date_based_show(rowData['originally_available_at']); if (!isNaN(parseInt(rowData['parent_media_index'])) && !isNaN(parseInt(rowData['media_index']))) { parent_info = ' (' + short_season(rowData['parent_title']) + ' · E' + rowData['media_index'] + ')'; } + else if (isNaN(parseInt(rowData['media_index'])) && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } else if (rowData['live'] && rowData['originally_available_at']) { parent_info = ' (' + rowData['originally_available_at'] + ')'; } media_type = ''; thumb_popover = '' + cellData + parent_info + ''; diff --git a/data/interfaces/default/library_recently_added.html b/data/interfaces/default/library_recently_added.html index fb53f9a5..8481f734 100644 --- a/data/interfaces/default/library_recently_added.html +++ b/data/interfaces/default/library_recently_added.html @@ -19,6 +19,7 @@ parent_title Returns the name of the artist. grandparent_title Returns the name of the show. media_index Returns the index number of the episode. parent_media_index Returns the index number of the season. +originally_available_at Returns the air date of the media item. section_id Returns the library section number of the media item. library_name Returns the library section name of the media item. year Returns the release year of the movie, episode, or album. @@ -32,7 +33,7 @@ DOCUMENTATION :: END % if data: <% - from plexpy.helpers import page, short_season + from plexpy.helpers import page, short_season, format_date_based_show %>
    @@ -78,8 +79,12 @@ DOCUMENTATION :: END ${item['title']}

    + % if item['media_index']: ${short_season(item['parent_title'])} · E${item['media_index']} + % else: + E${format_date_based_show(item['originally_available_at'])} + % endif

    % elif item['media_type'] == 'movie':

    diff --git a/data/interfaces/default/recently_added.html b/data/interfaces/default/recently_added.html index 52920817..7179b674 100644 --- a/data/interfaces/default/recently_added.html +++ b/data/interfaces/default/recently_added.html @@ -19,6 +19,7 @@ parent_title Returns the name of the artist. grandparent_title Returns the name of the show. media_index Returns the index number of the episode. parent_media_index Returns the index number of the season. +originally_available_at Returns the air date of the media item. section_id Returns the library section number of the media item. library_name Returns the library section name of the media item. year Returns the release year of the movie, episode, or album. @@ -32,7 +33,7 @@ DOCUMENTATION :: END % if data != None: <% - from plexpy.helpers import cast_to_int, page, short_season + from plexpy.helpers import cast_to_int, page, short_season, format_date_based_show %> % if data:
    @@ -146,9 +147,14 @@ DOCUMENTATION :: END ${item['title']}

    + % if item['media_index']: ${short_season(item['parent_title'])} · E${item['media_index']} + % else: + + E${format_date_based_show(item['originally_available_at'])} + % endif

    % elif item['media_type'] == 'album': diff --git a/data/interfaces/default/user_recently_watched.html b/data/interfaces/default/user_recently_watched.html index 39243766..f0176824 100644 --- a/data/interfaces/default/user_recently_watched.html +++ b/data/interfaces/default/user_recently_watched.html @@ -21,6 +21,7 @@ parent_title Returns the name of the artist. grandparent_title Returns the name of the show. media_index Returns the index number of the episode. parent_media_index Returns the index number of the season. +originally_available_at Returns the air date of the media item. year Returns the release year of the movie, episode, or album. DOCUMENTATION :: END @@ -28,7 +29,7 @@ DOCUMENTATION :: END % if data: <% - from plexpy.helpers import page, short_season + from plexpy.helpers import page, short_season, format_date_based_show %>
    @@ -59,6 +60,9 @@ DOCUMENTATION :: END
    % if item['media_type'] == 'episode': + % if not item['media_index']: + item['originally_available_at'] = format_date_based_show(item['originally_available_at']) + % endif % if item['live']:

    ${item['grandparent_title']} @@ -68,8 +72,12 @@ DOCUMENTATION :: END

    % if item['media_index']:

    + % if item['media_index']: ${short_season(item['parent_title'])} · E${item['media_index']} + % else: + E${item['originally_available_at']} + % endif

    % else:

    diff --git a/data/interfaces/newsletters/recently_added.html b/data/interfaces/newsletters/recently_added.html index e74d8463..2550c1bb 100644 --- a/data/interfaces/newsletters/recently_added.html +++ b/data/interfaces/newsletters/recently_added.html @@ -1,7 +1,7 @@ % if data: <% import plexpy - from plexpy.helpers import grouper, get_img_service + from plexpy.helpers import grouper, get_img_service, format_date_based_show recently_added = data['recently_added'] if plexpy.CONFIG.NEWSLETTER_SELF_HOSTED and plexpy.CONFIG.HTTP_BASE_URL: @@ -755,10 +755,13 @@

    % for i, season in enumerate(show['season'][:8]): % if season['episode_count'] == 1: - ${season['title']} · Episode ${season['episode'][0]['media_index']} - ${season['episode'][0]['title']} - % else: - ${season['title']} · Episodes ${season['episode_range']} - % endif + % if season['episode'][0]['media_index']: + ${season['title']} · Episode ${season['episode'][0]['media_index']} - ${season['episode'][0]['title']} + % else: + ${season['title']} · Episode ${format_date_based_show(season['episode'][0]['originally_available_at'])} + - ${season['episode'][0]['title']} + ${season['title']} · Episodes ${season['episode_range']} + % endif % if i < min(show['season_count'], 7):
    % elif i == 7 and show['season_count'] > 8: diff --git a/plexpy/common.py b/plexpy/common.py index 33b4cc00..c264c1ac 100644 --- a/plexpy/common.py +++ b/plexpy/common.py @@ -508,6 +508,7 @@ NOTIFICATION_PARAMETERS = [ {'name': 'Season Number', 'type': 'int', 'value': 'season_num', 'description': 'The season number.', 'example': 'e.g. 1, or 1-3'}, {'name': 'Season Number 00', 'type': 'int', 'value': 'season_num00', 'description': 'The two digit season number.', 'example': 'e.g. 01, or 01-03'}, {'name': 'Episode Number', 'type': 'int', 'value': 'episode_num', 'description': 'The episode number.', 'example': 'e.g. 6, or 6-10'}, + {'name': 'Episode Number', 'type': 'str', 'value': 'episode_date', 'description': 'The episode number of date based tv shows (in date format).'}, {'name': 'Episode Number 00', 'type': 'int', 'value': 'episode_num00', 'description': 'The two digit episode number.', 'example': 'e.g. 06, or 06-10'}, {'name': 'Disc Number', 'type': 'int', 'value': 'disc_num', 'description': 'The disc number.', 'example': 'e.g. 2'}, {'name': 'Disc Number 00', 'type': 'int', 'value': 'disc_num00', 'description': 'The two digit disc number.', 'example': 'e.g. 02'}, diff --git a/plexpy/helpers.py b/plexpy/helpers.py index b0995849..a086b83c 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -31,6 +31,7 @@ from collections import OrderedDict import datetime from functools import reduce, wraps import hashlib +import html import imghdr from future.moves.itertools import islice, zip_longest import ipwhois @@ -418,6 +419,8 @@ def clean_filename(filename, replace='_'): cleaned_filename = ''.join(c if c in whitelist else replace for c in cleaned_filename) return cleaned_filename +def format_date_based_show(date): + return str(date).replace('-', html.unescape('·')) def split_strip(s, delimiter=','): return [x.strip() for x in str(s).split(delimiter) if x.strip()] diff --git a/plexpy/libraries.py b/plexpy/libraries.py index 8a51eec1..fbf4957f 100644 --- a/plexpy/libraries.py +++ b/plexpy/libraries.py @@ -539,6 +539,7 @@ class Libraries(object): # If no cache was imported, get all library children items cached_items = {d['rating_key']: d['file_size'] for d in rows} if not refresh else {} + # TODO: Auto trigger for update - needs to be triggered to get date based episode support if refresh or not rows: pms_connect = pmsconnect.PmsConnect() @@ -577,6 +578,7 @@ class Libraries(object): 'year': item['year'], 'media_index': item['media_index'], 'parent_media_index': item['parent_media_index'], + 'originally_available_at': item['originally_available_at'], 'thumb': item['thumb'], 'container': item.get('container', ''), 'bitrate': item.get('bitrate', ''), diff --git a/plexpy/newsletters.py b/plexpy/newsletters.py index 902eb69b..a652fe27 100644 --- a/plexpy/newsletters.py +++ b/plexpy/newsletters.py @@ -766,6 +766,8 @@ class RecentlyAdded(Newsletter): for (index, title), children in groupby(filtered_children, key=lambda x: (x['parent_media_index'], x['parent_title'])): episodes = list(children) + #TODO How do we want to display the episode range in the newsletter + num, num00 = format_group_index([helpers.cast_to_int(d['media_index']) for d in episodes]) seasons.append({'media_index': index, diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 57f5ff83..ee560c83 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -912,8 +912,11 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m track_name = notify_params['title'] season_num = str(notify_params['parent_media_index']).zfill(1) season_num00 = str(notify_params['parent_media_index']).zfill(2) - episode_num = str(notify_params['media_index']).zfill(1) - episode_num00 = str(notify_params['media_index']).zfill(2) + if notify_params['media_index']: + episode_num = str(notify_params['media_index']).zfill(1) + episode_num00 = str(notify_params['media_index']).zfill(2) + else: + episode_num = episode_num00 = helpers.format_date_based_show(notify_params['originally_available_at']) disc_num = str(notify_params['parent_media_index']).zfill(1) disc_num00 = str(notify_params['parent_media_index']).zfill(2) track_num = str(notify_params['media_index']).zfill(1) diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index 11142873..906ad3c3 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -2821,6 +2821,7 @@ class PmsConnect(object): 'sort_title': helpers.get_xml_attr(item, 'titleSort'), 'media_index': helpers.get_xml_attr(item, 'index'), 'parent_media_index': helpers.get_xml_attr(item, 'parentIndex'), + 'originally_available_at': helpers.get_xml_attr(item, 'originallyAvailableAt'), 'year': helpers.get_xml_attr(item, 'year'), 'thumb': helpers.get_xml_attr(item, 'thumb'), 'parent_thumb': helpers.get_xml_attr(item, 'thumb'), diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 76c44243..8d14b41d 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -792,6 +792,7 @@ class WebInterface(object): "media_type": "show", "parent_media_index": "", "parent_rating_key": "", + "originally_available_at": "2011-08-21", "play_count": 15, "rating_key": "1219", "section_id": 2, From 09c7c36c02a450b25a2cb65a29b723a912270310 Mon Sep 17 00:00:00 2001 From: herby2212 <12448284+herby2212@users.noreply.github.com> Date: Tue, 3 Jan 2023 06:30:53 +0100 Subject: [PATCH 2/8] fix info --- data/interfaces/default/info.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index 8a81b36c..faa1e36f 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -260,7 +260,6 @@ DOCUMENTATION :: END

    % endif % endif - % endif % elif data['media_type'] in ('movie', 'show', 'artist', 'collection', 'playlist', 'photo_album'):

     

    ${data['title']}

    % elif data['media_type'] == 'season': @@ -269,7 +268,7 @@ DOCUMENTATION :: END % elif data['media_type'] == 'episode':

    ${data['grandparent_title']}

    ${data['title']}

    - % if data['media_index']: + % if data['media_index']: % else: From f329f960cb786ea42b47715e1e711296aeb56a1b Mon Sep 17 00:00:00 2001 From: herby2212 <12448284+herby2212@users.noreply.github.com> Date: Tue, 3 Jan 2023 06:53:40 +0100 Subject: [PATCH 3/8] settings addition --- data/interfaces/default/settings.html | 9 +++++++++ plexpy/config.py | 2 ++ plexpy/helpers.py | 1 + 3 files changed, 12 insertions(+) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index f7c24211..764081bb 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -126,6 +126,15 @@

    Set your preferred time format. Click here to see the parameter list.

    +
    + +
    +
    + +
    +
    +

    Set your preferred display format for date based tv shows.

    +