Skip to content

Commit b1d2031

Browse files
committed
v0.2
Created the GenerateMenu function, which reads in a dictionary of menu items, and turns them into DirectoryObjects and returns them in a ObjectContainer. Used this function everywhere I could to cut down on repetition and lines of code. Created a language file to hold some string constants. But most importantly, I found some artwork to use as the background... And I couldn't decide which one to use so I have 2 alternates sitting in the Resources folder. In v0.3 I plan to create preferences for artwork (and other options), as well as fix up the MemberMenu function to filter out empty directories.
1 parent 17a4ec3 commit b1d2031

13 files changed

+183
-247
lines changed

Contents/Code/PHCategories.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
PH_CATEGORIES_ALPHABETICAL_URL = PH_CATEGORIES_URL + '?o=al'
55

66
@route(ROUTE_PREFIX + '/categories')
7-
def BrowseCategories(title, url = PH_CATEGORIES_ALPHABETICAL_URL):
7+
def BrowseCategories(title=PH_DEFAULT_BROWSE_CATEGORIES_TITLE, url = PH_CATEGORIES_ALPHABETICAL_URL):
88

9-
# Create the object to contain all of the categories
10-
oc = ObjectContainer(title2=title)
9+
# Create a dictionary of menu items
10+
browseCategoriesMenuItems = OrderedDict()
1111

1212
# Get the HTML of the page
1313
html = HTML.ElementFromURL(url)
@@ -18,15 +18,12 @@ def BrowseCategories(title, url = PH_CATEGORIES_ALPHABETICAL_URL):
1818
# Loop through all categories
1919
for category in categories:
2020

21+
# Use xPath to extract category details
2122
categoryTitle = category.xpath("./h5/a/strong/text()")[0]
2223
categoryURL = BASE_URL + category.xpath("./h5/a/@href")[0]
2324
categoryThumbnail = category.xpath("./a/img/@src")[0]
2425

25-
# Add a Directory Object for the category
26-
oc.add(DirectoryObject(
27-
key = Callback(SortVideos, title=categoryTitle, url=categoryURL),
28-
title = categoryTitle,
29-
thumb = categoryThumbnail
30-
))
26+
# Add a menu item for the category
27+
browseCategoriesMenuItems[categoryTitle] = {'function':SortVideos, 'functionArgs':{'url':categoryURL}, 'directoryObjectArgs':{'thumb':categoryThumbnail}}
3128

32-
return oc
29+
return GenerateMenu(title, browseCategoriesMenuItems)

Contents/Code/PHChannels.py

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,24 @@
55
MAX_CHANNELS_PER_PAGE = 36
66

77
@route(ROUTE_PREFIX + '/channels')
8-
def BrowseChannels(title):
9-
10-
oc = ObjectContainer(title2=title)
11-
12-
oc.add(InputDirectoryObject(
13-
key = Callback(SearchChannels, title='Search Results'),
14-
title = "Search Channels",
15-
prompt = "Search for...",
16-
summary = "Enter Channel Search Terms"
17-
))
18-
19-
channelSortOrders = OrderedDict([
20-
('Most Popular', {'o':'rk'}),
21-
('Trending', {'o':'tr'}),
22-
('Most Recent', {'o':'mr'}),
23-
('A-Z', {'o':'al'})
8+
def BrowseChannels(title=PH_DEFAULT_BROWSE_CHANNELS_TITLE):
9+
10+
# Create a dictionary of menu items
11+
browseChannelsMenuItems = OrderedDict([
12+
('Search Channels', {'function':SearchChannels, 'search':True, 'directoryObjectArgs':{'prompt':'Search for...','summary':'Enter Channel Search Terms'}}),
13+
('Most Popular', {'function':ListChannels, 'functionArgs':{'url':addURLParameters(PH_CHANNELS_URL, {'o':'rk'})}}),
14+
('Trending', {'function':ListChannels, 'functionArgs':{'url':addURLParameters(PH_CHANNELS_URL, {'o':'tr'})}}),
15+
('Most Recent', {'function':ListChannels, 'functionArgs':{'url':addURLParameters(PH_CHANNELS_URL, {'o':'mr'})}}),
16+
('A-Z', {'function':ListChannels, 'functionArgs':{'url':addURLParameters(PH_CHANNELS_URL, {'o':'al'})}})
2417
])
2518

26-
for channelSortOrder, urlParams in channelSortOrders.items():
27-
oc.add(DirectoryObject(
28-
key = Callback(ListChannels, title=channelSortOrder, url=addURLParameters(PH_CHANNELS_URL, urlParams)),
29-
title = channelSortOrder
30-
))
31-
32-
return oc
19+
return GenerateMenu(title, browseChannelsMenuItems)
3320

3421
@route(ROUTE_PREFIX + '/channels/list')
3522
def ListChannels(title, url = PH_CHANNELS_URL, page=1):
3623

37-
# Create the object to contain all of the channels
38-
oc = ObjectContainer(title2=title)
24+
# Create a dictionary of menu items
25+
listChannelsMenuItems = OrderedDict()
3926

4027
# Add the page number into the query string
4128
if (int(page) != 1):
@@ -50,28 +37,22 @@ def ListChannels(title, url = PH_CHANNELS_URL, page=1):
5037
# Loop through all channels
5138
for channel in channels:
5239

40+
# Use xPath to extract channel details
5341
channelTitle = channel.xpath("./div[contains(@class, 'description')]/div[contains(@class, 'descriptionContainer')]/ul/li/a[contains(@class, 'usernameLink')]/text()")[0]
5442
channelURL = BASE_URL + channel.xpath("./div[contains(@class, 'description')]/div[contains(@class, 'descriptionContainer')]/ul/li/a[contains(@class, 'usernameLink')]/@href")[0]
5543
channelThumbnail = channel.xpath("./div[contains(@class,'description')]/div[contains(@class, 'avatar')]/a/img/@src")[0]
5644

57-
# Add a Directory Object for the channels
58-
oc.add(DirectoryObject(
59-
key = Callback(SortVideos, title=channelTitle, url=channelURL + '/videos'),
60-
title = channelTitle,
61-
thumb = channelThumbnail
62-
))
45+
# Add a menu item for the channel
46+
listChannelsMenuItems[channelTitle] = {'function':SortVideos, 'functionArgs':{'url':channelURL + '/videos'}, 'directoryObjectArgs':{'thumb':channelThumbnail}}
6347

6448
# There is a slight change that this will break... If the number of videos returned in total is divisible by MAX_VIDEOS_PER_PAGE with no remainder, there could possibly be no additional page after. This is unlikely though and I'm too lazy to handle it.
6549
if (len(channels) == MAX_CHANNELS_PER_PAGE):
66-
oc.add(NextPageObject(
67-
key = Callback(ListChannels, title=title, url=url, page = int(page)+1),
68-
title = 'Next Page'
69-
))
50+
listChannelsMenuItems['Next Page'] = {'function':ListChannels, 'functionArgs':{'title':title, 'url':url, 'page':int(page)+1}, 'nextPage':True}
7051

71-
return oc
52+
return GenerateMenu(title, listChannelsMenuItems)
7253

7354
@route(ROUTE_PREFIX + '/channels/search')
74-
def SearchChannels(query, title):
55+
def SearchChannels(query):
7556

7657
# Format the query for use in PornHub's search
7758
formattedQuery = formatStringForSearch(query, "+")

Contents/Code/PHCommon.py

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import urllib
22
import urlparse
33
from collections import OrderedDict
4+
from PHLanguageEN import *
45

56
ROUTE_PREFIX = '/video/pornhub'
67

@@ -38,7 +39,7 @@
3839
])
3940

4041
@route(ROUTE_PREFIX + '/list')
41-
def ListVideos(title, url, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
42+
def ListVideos(title=PH_DEFAULT_LIST_VIDEOS_TITLE, url=PH_VIDEO_URL, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
4243

4344
# Create the object to contain all of the videos
4445
oc = ObjectContainer(title2 = title)
@@ -47,6 +48,7 @@ def ListVideos(title, url, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
4748
if (int(page) != 1):
4849
url = addURLParameters(url, {'page':str(page)})
4950

51+
# This could definitely be handled more gracefully. But it works for now
5052
if ("/channels/" in url):
5153
pageLimit = MAX_VIDEOS_PER_CHANNEL_PAGE
5254
elif ("/video/search" in url):
@@ -57,22 +59,16 @@ def ListVideos(title, url, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
5759
# Get the HTML of the site
5860
html = HTML.ElementFromURL(url)
5961

60-
Log(HTML.StringFromElement(html))
61-
6262
# Use xPath to extract a list of divs that contain videos
6363
videos = html.xpath("//li[contains(@class,'videoblock')]")
6464

6565
# This piece of code is ridiculous. From the best I can gether, the poorly formed HTML on PornHub makes xPath choke at 123 videos. So I rounded it down to 120 and limited the videos to that. This should only affect playlists, but it is a really ridiculous problem
6666
if (len(videos) >= 120):
6767
videos = videos[0:119]
6868

69-
Log ('There are ' + str(len(videos)) + ' videos')
70-
7169
# Loop through the videos in the page
7270
for video in videos:
7371

74-
#Log (HTML.StringFromElement(video))
75-
7672
# Get the link of the video
7773
videoURL = video.xpath("./div/div/a/@href")[0]
7874

@@ -82,7 +78,7 @@ def ListVideos(title, url, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
8278

8379
# Make sure the last step went smoothly (this is probably redundant but oh well)
8480
if (videoURL.startswith(BASE_URL)):
85-
# Get the video details
81+
# Use xPath to extract video details
8682
videoTitle = video.xpath("./div/div/a/div[contains(@class, 'thumbnail-info-wrapper')]/span[@class='title']/a/text()")[0]
8783
thumbnail = video.xpath("./div/div/a/div[@class='img']/img/@data-mediumthumb")[0]
8884

@@ -130,35 +126,73 @@ def ListVideos(title, url, page=1, pageLimit = MAX_VIDEOS_PER_PAGE):
130126
return oc
131127

132128
@route(ROUTE_PREFIX + '/sort')
133-
def SortVideos(title, url = PH_VIDEO_URL, sortOrders = SORT_ORDERS):
134-
135-
# Create the object to contain all of the sorting options
136-
oc = ObjectContainer(title2 = title)
129+
def SortVideos(title=PH_DEFAULT_SORT_VIDEOS_TITLE, url = PH_VIDEO_URL, sortOrders = SORT_ORDERS):
137130

131+
# If sorting channels, use a different dictionary of sort orders
138132
if ("/channels/" in url):
139133
sortOrders = CHANNEL_VIDEOS_SORT_ORDERS
140134

135+
# Create a dictionary of menu items
136+
sortVideosMenuItems = OrderedDict()
137+
141138
# Add the sorting options
142139
for sortTitle, urlParams in sortOrders.items():
143140

144-
oc.add(DirectoryObject(
145-
key = Callback(ListVideos, title=sortTitle, url=addURLParameters(url, urlParams)),
146-
title = title + ' - ' + sortTitle
147-
))
141+
# Add a menu item for the category
142+
sortVideosMenuItems[sortTitle] = {'function':ListVideos, 'functionArgs':{'url':addURLParameters(url, urlParams)}}
148143

149-
return oc
144+
return GenerateMenu(title, sortVideosMenuItems)
150145

151146
@route(ROUTE_PREFIX + '/search')
152-
def SearchVideos(query, title):
147+
def SearchVideos(query):
153148

154149
# Format the query for use in PornHub's search
155150
formattedQuery = formatStringForSearch(query, "+")
156151

157152
try:
158-
return ListVideos(title='Search Results for ' + query, url=PH_VIDEO_SEARCH_URL % formattedQuery)
153+
return ListVideos(title='Search Results For ' + query, url=PH_VIDEO_SEARCH_URL % formattedQuery)
159154
except:
160155
return ObjectContainer(header='Search Results', message="No search results found", no_cache=True)
161156

157+
def GenerateMenu(title, menuItems):
158+
# Create the object to contain the menu items
159+
oc = ObjectContainer(title2=title)
160+
161+
# Loop through the menuItems dictionary
162+
for menuTitle, menuData in menuItems.items():
163+
# Create empty dictionaries to hold the arguments for the Directory Object and the Function
164+
directoryObjectArgs = {}
165+
functionArgs = {}
166+
167+
# See if any Directory Object arguments are present in the menu data
168+
if ('directoryObjectArgs' in menuData):
169+
# Merge dictionaries
170+
directoryObjectArgs.update(menuData['directoryObjectArgs'])
171+
172+
# Check to see if the menu item is a search menu item
173+
if ('search' in menuData and menuData['search'] == True):
174+
directoryObject = InputDirectoryObject(title=menuTitle, **directoryObjectArgs)
175+
# Check to see if the menu item is a next page item
176+
elif ('nextPage' in menuData and menuData['nextPage'] == True):
177+
directoryObject = NextPageObject(title=menuTitle, **directoryObjectArgs)
178+
# Otherwise, use a basic Directory Object
179+
else:
180+
directoryObject = DirectoryObject(title=menuTitle, **directoryObjectArgs)
181+
functionArgs['title'] = menuTitle
182+
183+
# See if any Function arguments are present in the menu data
184+
if ('functionArgs' in menuData):
185+
# Merge dictionaries
186+
functionArgs.update(menuData['functionArgs'])
187+
188+
# Set the Directory Object key to the function from the menu data, passing along any additional function arguments
189+
directoryObject.key = Callback(menuData['function'], **functionArgs)
190+
191+
# Add the Directory Object to the Object Container
192+
oc.add(directoryObject)
193+
194+
return oc
195+
162196
# I stole this function from http://stackoverflow.com/questions/2506379/add-params-to-given-url-in-python. It works.
163197
def addURLParameters (url, params):
164198

@@ -168,7 +202,7 @@ def addURLParameters (url, params):
168202
urlQuery.update(params)
169203

170204
# So... PornHub requires that it's query string parameters are set in the right order... for some reason. This piece of code handles that. It's retarded, but it has to be done
171-
urlQueryOrder = ['c', 'channelSearch', 'search', 'o', 't', 'page']
205+
urlQueryOrder = ['c', 'channelSearch', 'search', 'username', 'o', 't', 'page']
172206

173207
urlQueryOrdered = OrderedDict()
174208

@@ -180,6 +214,7 @@ def addURLParameters (url, params):
180214

181215
return urlparse.urlunparse(urlParts)
182216

217+
# I stole this function (and everything I did for search basically) from the RedTube Plex Plugin, this file specifically https://github.com/flownex/RedTube.bundle/blob/master/Contents/Code/PCbfSearch.py
183218
def formatStringForSearch(query, delimiter):
184219
query = String.StripTags(str(query))
185220
query = query.replace('%20',' ')

Contents/Code/PHLanguageEN.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
PH_DEFAULT_LIST_VIDEOS_TITLE = "Browse Videos"
2+
PH_DEFAULT_SORT_VIDEOS_TITLE = "Sort Videos"
3+
PH_DEFAULT_BROWSE_CATEGORIES_TITLE = "Browse Categories"
4+
PH_DEFAULT_BROWSE_CHANNELS_TITLE = "Browse Channels"
5+
PH_DEFAULT_BROWSE_PORN_STARS_TITLE = "Browse Porn Stars"
6+
PH_DEFAULT_BROWSE_PLAYLISTS_TITLE = "Browse Playlists"
7+
PH_DEFAULT_BROWSE_MEMBERS_TITLE = "Browse Members"

0 commit comments

Comments
 (0)