Skip to content
This repository was archived by the owner on Oct 21, 2024. It is now read-only.

Commit b33062b

Browse files
Add categories and clips (#23)
1 parent 40af262 commit b33062b

File tree

12 files changed

+514
-104
lines changed

12 files changed

+514
-104
lines changed

resources/language/resource.language.en_gb/strings.po

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ msgctxt "#30056"
6464
msgid "Browse the Catalog for [B]{channel}[/B]"
6565
msgstr ""
6666

67+
msgctxt "#30057"
68+
msgid "Categories for [B]{channel}[/B]"
69+
msgstr ""
70+
71+
msgctxt "#30058"
72+
msgid "Browse the Categories for [B]{channel}[/B]"
73+
msgstr ""
74+
75+
msgctxt "#30059"
76+
msgid "Clips of [B]{program}[/B]"
77+
msgstr ""
78+
79+
msgctxt "#30060"
80+
msgid "Watch short clips of [B]{program}[/B]"
81+
msgstr ""
82+
6783

6884
### CONTEXT MENU
6985
msgctxt "#30102"

resources/language/resource.language.nl_nl/strings.po

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ msgctxt "#30056"
6565
msgid "Browse the Catalog for [B]{channel}[/B]"
6666
msgstr "Doorblader de catalogus voor [B]{channel}[/B]"
6767

68+
msgctxt "#30057"
69+
msgid "Categories for [B]{channel}[/B]"
70+
msgstr "Categoriën voor [B]{channel}[/B]"
71+
72+
msgctxt "#30058"
73+
msgid "Browse the Categories for [B]{channel}[/B]"
74+
msgstr "Doorblader de categoriën van [B]{channel}[/B]"
75+
76+
msgctxt "#30059"
77+
msgid "Clips of [B]{program}[/B]"
78+
msgstr "Clips van [B]{program}[/B]"
79+
80+
msgctxt "#30060"
81+
msgid "Watch short clips of [B]{program}[/B]"
82+
msgstr "Bekijk korte videoclips van [B]{program}[/B]"
83+
6884

6985
### CONTEXT MENU
7086
msgctxt "#30102"

resources/lib/addon.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,32 @@ def show_channel_menu(channel):
3535
Channels().show_channel_menu(channel)
3636

3737

38-
@routing.route('/tvguide/channel/<channel>')
39-
def show_tvguide_channel(channel):
38+
@routing.route('/channels/<channel>/categories')
39+
def show_channel_categories(channel):
40+
""" Shows TV Channel categories """
41+
from resources.lib.modules.channels import Channels
42+
Channels().show_channel_categories(channel)
43+
44+
45+
@routing.route('/channels/<channel>/categories/<category>')
46+
def show_channel_category(channel, category):
47+
""" Shows TV Channel categories """
48+
from resources.lib.modules.channels import Channels
49+
Channels().show_channel_category(channel, category)
50+
51+
52+
@routing.route('/channels/<channel>/tvguide')
53+
def show_channel_tvguide(channel):
4054
""" Shows the dates in the tv guide """
4155
from resources.lib.modules.tvguide import TvGuide
42-
TvGuide().show_tvguide_channel(channel)
56+
TvGuide().show_channel(channel)
4357

4458

45-
@routing.route('/tvguide/channel/<channel>/<date>')
46-
def show_tvguide_detail(channel=None, date=None):
59+
@routing.route('/channels/<channel>/tvguide/<date>')
60+
def show_channel_tvguide_detail(channel=None, date=None):
4761
""" Shows the programs of a specific date in the tv guide """
4862
from resources.lib.modules.tvguide import TvGuide
49-
TvGuide().show_tvguide_detail(channel, date)
63+
TvGuide().show_detail(channel, date)
5064

5165

5266
@routing.route('/catalog')
@@ -56,23 +70,30 @@ def show_catalog():
5670
Catalog().show_catalog()
5771

5872

59-
@routing.route('/catalog/by-channel/<channel>')
60-
def show_catalog_channel(channel):
73+
@routing.route('/catalog/<channel>')
74+
def show_channel_catalog(channel):
6175
""" Show a category in the catalog """
6276
from resources.lib.modules.catalog import Catalog
6377
Catalog().show_catalog_channel(channel)
6478

6579

66-
@routing.route('/catalog/program/<channel>/<program>')
80+
@routing.route('/catalog/<channel>/<program>')
6781
def show_catalog_program(channel, program):
6882
""" Show a program from the catalog """
6983
from resources.lib.modules.catalog import Catalog
7084
Catalog().show_program(channel, program)
7185

7286

73-
@routing.route('/catalog/program/<channel>/<program>/<season>')
87+
@routing.route('/catalog/<channel>/<program>/clips')
88+
def show_catalog_program_clips(channel, program):
89+
""" Show the clips from a program """
90+
from resources.lib.modules.catalog import Catalog
91+
Catalog().show_program_clips(channel, program)
92+
93+
94+
@routing.route('/catalog/<channel>/<program>/season/<season>')
7495
def show_catalog_program_season(channel, program, season):
75-
""" Show a program from the catalog """
96+
""" Show a season from a program """
7697
from resources.lib.modules.catalog import Catalog
7798
Catalog().show_program_season(channel, program, season)
7899

resources/lib/modules/catalog.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def __init__(self):
2222
""" Initialise object """
2323
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path())
2424
self._api = ContentApi(auth, cache_path=kodiutils.get_cache_path())
25-
self._menu = Menu()
2625

2726
def show_catalog(self):
2827
""" Show all the programs of all channels """
@@ -34,7 +33,7 @@ def show_catalog(self):
3433
kodiutils.notification(message=str(ex))
3534
raise
3635

37-
listing = [self._menu.generate_titleitem(item) for item in items]
36+
listing = [Menu.generate_titleitem(item) for item in items]
3837

3938
# Sort items by title
4039
# Used for A-Z listing or when movies and episodes are mixed.
@@ -52,7 +51,7 @@ def show_catalog_channel(self, channel):
5251

5352
listing = []
5453
for item in items:
55-
listing.append(self._menu.generate_titleitem(item))
54+
listing.append(Menu.generate_titleitem(item))
5655

5756
# Sort items by title
5857
# Used for A-Z listing or when movies and episodes are mixed.
@@ -64,19 +63,19 @@ def show_program(self, channel, program_id):
6463
:type program_id: str
6564
"""
6665
try:
67-
program = self._api.get_program(channel, program_id, cache=CACHE_PREVENT) # Use CACHE_PREVENT since we want fresh data
66+
program = self._api.get_program(channel, program_id, extract_clips=True, cache=CACHE_PREVENT) # Use CACHE_PREVENT since we want fresh data
6867
except UnavailableException:
6968
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
7069
kodiutils.end_of_directory()
7170
return
7271

73-
if not program.episodes:
72+
if not program.episodes and not program.clips:
7473
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
7574
kodiutils.end_of_directory()
7675
return
7776

78-
# Go directly to the season when we have only one season
79-
if len(program.seasons) == 1:
77+
# Go directly to the season when we have only one season and no clips
78+
if not program.clips and len(program.seasons) == 1:
8079
self.show_program_season(channel, program_id, list(program.seasons.values())[0].uuid)
8180
return
8281

@@ -85,7 +84,7 @@ def show_program(self, channel, program_id):
8584
listing = []
8685

8786
# Add an '* All seasons' entry when configured in Kodi
88-
if kodiutils.get_global_setting('videolibrary.showallitems') is True:
87+
if program.seasons and kodiutils.get_global_setting('videolibrary.showallitems') is True:
8988
listing.append(
9089
TitleItem(
9190
title='* %s' % kodiutils.localize(30204), # * All seasons
@@ -122,6 +121,25 @@ def show_program(self, channel, program_id):
122121
)
123122
)
124123

124+
# Add Clips
125+
if program.clips:
126+
listing.append(
127+
TitleItem(
128+
title=kodiutils.localize(30059, program=program.title), # Clips for {program}
129+
path=kodiutils.url_for('show_catalog_program_clips', channel=channel, program=program_id),
130+
art_dict={
131+
'fanart': program.background,
132+
},
133+
info_dict={
134+
'tvshowtitle': program.title,
135+
'title': kodiutils.localize(30059, program=program.title), # Clips for {program}
136+
'plot': kodiutils.localize(30060, program=program.title), # Watch short clips of {program}
137+
'set': program.title,
138+
'studio': studio,
139+
}
140+
)
141+
)
142+
125143
# Sort by label. Some programs return seasons unordered.
126144
kodiutils.show_listing(listing, 30003, content='tvshows')
127145

@@ -145,7 +163,25 @@ def show_program_season(self, channel, program_id, season_uuid):
145163
# Show the episodes of the season that was selected
146164
episodes = [e for e in program.episodes if e.season_uuid == season_uuid]
147165

148-
listing = [self._menu.generate_titleitem(episode) for episode in episodes]
166+
listing = [Menu.generate_titleitem(episode) for episode in episodes]
149167

150168
# Sort by episode number by default. Takes seasons into account.
151169
kodiutils.show_listing(listing, 30003, content='episodes', sort=['episode', 'duration'])
170+
171+
def show_program_clips(self, channel, program_id):
172+
""" Show the clips of a program from the catalog
173+
:type channel: str
174+
:type program_id: str
175+
"""
176+
try:
177+
# We need to query the backend, since we don't cache clips.
178+
program = self._api.get_program(channel, program_id, extract_clips=True, cache=CACHE_PREVENT)
179+
except UnavailableException:
180+
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the catalogue.
181+
kodiutils.end_of_directory()
182+
return
183+
184+
listing = [Menu.generate_titleitem(episode) for episode in program.clips]
185+
186+
# Sort like we get our results back.
187+
kodiutils.show_listing(listing, 30003, content='episodes')

resources/lib/modules/channels.py

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
from resources.lib import kodiutils
99
from resources.lib.kodiutils import TitleItem
10+
from resources.lib.modules.menu import Menu
1011
from resources.lib.viervijfzes import CHANNELS, STREAM_DICT
12+
from resources.lib.viervijfzes.auth import AuthApi
13+
from resources.lib.viervijfzes.content import ContentApi, CACHE_ONLY, CACHE_AUTO
1114

1215
_LOGGER = logging.getLogger('channels')
1316

@@ -17,6 +20,8 @@ class Channels:
1720

1821
def __init__(self):
1922
""" Initialise object """
23+
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path())
24+
self._api = ContentApi(auth, cache_path=kodiutils.get_cache_path())
2025

2126
@staticmethod
2227
def show_channels():
@@ -33,7 +38,7 @@ def show_channels():
3338
(
3439
kodiutils.localize(30053, channel=channel.get('name')), # TV Guide for {channel}
3540
'Container.Update(%s)' %
36-
kodiutils.url_for('show_tvguide_channel', channel=channel.get('epg'))
41+
kodiutils.url_for('show_channel_tvguide', channel=channel.get('epg'))
3742
)
3843
]
3944

@@ -60,43 +65,54 @@ def show_channels():
6065
kodiutils.show_listing(listing, 30007)
6166

6267
@staticmethod
63-
def show_channel_menu(key):
68+
def show_channel_menu(channel):
6469
""" Shows a TV channel
65-
:type key: str
70+
:type channel: str
6671
"""
67-
channel = CHANNELS[key]
72+
channel_info = CHANNELS[channel]
6873

6974
# Lookup the high resolution logo based on the channel name
70-
fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel.get('background'))
75+
fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel_info.get('background'))
7176

7277
listing = [
7378
TitleItem(
74-
title=kodiutils.localize(30053, channel=channel.get('name')), # TV Guide for {channel}
75-
path=kodiutils.url_for('show_tvguide_channel', channel=key),
79+
title=kodiutils.localize(30053, channel=channel_info.get('name')), # TV Guide for {channel}
80+
path=kodiutils.url_for('show_channel_tvguide', channel=channel),
7681
art_dict={
7782
'icon': 'DefaultAddonTvInfo.png',
7883
'fanart': fanart,
7984
},
8085
info_dict={
81-
'plot': kodiutils.localize(30054, channel=channel.get('name')), # Browse the TV Guide for {channel}
86+
'plot': kodiutils.localize(30054, channel=channel_info.get('name')), # Browse the TV Guide for {channel}
8287
}
8388
),
8489
TitleItem(
85-
title=kodiutils.localize(30055, channel=channel.get('name')), # Catalog for {channel}
86-
path=kodiutils.url_for('show_catalog_channel', channel=key),
90+
title=kodiutils.localize(30055, channel=channel_info.get('name')), # Catalog for {channel}
91+
path=kodiutils.url_for('show_channel_catalog', channel=channel),
8792
art_dict={
8893
'icon': 'DefaultMovieTitle.png',
8994
'fanart': fanart,
9095
},
9196
info_dict={
92-
'plot': kodiutils.localize(30056, channel=channel.get('name')), # Browse the Catalog for {channel}
97+
'plot': kodiutils.localize(30056, channel=channel_info.get('name')), # Browse the Catalog for {channel}
9398
}
94-
)
99+
),
100+
TitleItem(
101+
title=kodiutils.localize(30057, channel=channel_info.get('name')), # Categories for {channel}
102+
path=kodiutils.url_for('show_channel_categories', channel=channel),
103+
art_dict={
104+
'icon': 'DefaultGenre.png',
105+
'fanart': fanart,
106+
},
107+
info_dict={
108+
'plot': kodiutils.localize(30058, channel=channel_info.get('name')), # Browse the Categories for {channel}
109+
}
110+
),
95111
]
96112

97113
# Add YouTube channels
98114
if kodiutils.get_cond_visibility('System.HasAddon(plugin.video.youtube)') != 0:
99-
for youtube in channel.get('youtube', []):
115+
for youtube in channel_info.get('youtube', []):
100116
listing.append(
101117
TitleItem(
102118
title=kodiutils.localize(30206, label=youtube.get('label')), # Watch {label} on YouTube
@@ -108,3 +124,58 @@ def show_channel_menu(key):
108124
)
109125

110126
kodiutils.show_listing(listing, 30007, sort=['unsorted'])
127+
128+
def show_channel_categories(self, channel):
129+
""" Shows the categories of a channel
130+
:type channel: str
131+
"""
132+
categories = self._api.get_categories(channel)
133+
134+
listing = [
135+
TitleItem(
136+
title=category.title,
137+
path=kodiutils.url_for('show_channel_category', channel=category.channel, category=category.uuid),
138+
art_dict={
139+
'icon': 'DefaultGenre.png',
140+
},
141+
) for category in categories
142+
]
143+
144+
kodiutils.show_listing(listing, 30007, sort=['unsorted'])
145+
146+
def show_channel_category(self, channel, category_id):
147+
""" Shows a selected category of a channel
148+
:type channel: str
149+
:type category_id: str
150+
"""
151+
categories = self._api.get_categories(channel)
152+
153+
# Extract selected category
154+
category = next(category for category in categories if category.uuid == category_id)
155+
if not category:
156+
raise Exception('Unknown category')
157+
158+
# Add programs
159+
listing_programs = []
160+
for item in category.programs:
161+
program = self._api.get_program(channel, item.path, CACHE_ONLY) # Get program details, but from cache only
162+
163+
if program:
164+
listing_programs.append(Menu.generate_titleitem(program))
165+
else:
166+
listing_programs.append(Menu.generate_titleitem(item))
167+
168+
# Add episodes
169+
listing_episodes = []
170+
for item in category.episodes:
171+
# We don't have the Program Name without making a request to the page, so we use CACHE_AUTO instead of CACHE_ONLY.
172+
# This will make a request for each item in this view (about 12 items), but it goes quite fast.
173+
# Results are cached, so this will only happen once.
174+
episode = self._api.get_episode(channel, item.path, CACHE_AUTO)
175+
176+
if episode:
177+
listing_episodes.append(Menu.generate_titleitem(episode))
178+
else:
179+
listing_episodes.append(Menu.generate_titleitem(item))
180+
181+
kodiutils.show_listing(listing_programs + listing_episodes, 30007, content='tvshows', sort=['unsorted'])

0 commit comments

Comments
 (0)