Advertisement
Guest User

Untitled

a guest
Jul 7th, 2023
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.36 KB | None | 0 0
  1. #region Import the necessary modules from the Kodi framework and external libraries
  2. import os
  3. import xbmc
  4. import xbmcaddon
  5. import xbmcgui
  6. import xbmcvfs
  7.  
  8. import requests
  9. from PIL import Image, ImageDraw, ImageFont, ImageOps, ImageColor
  10. from io import BytesIO
  11. #endregion
  12.  
  13. #region Define the SportsAPI class
  14. class SportsAPI:
  15. def __init__(self, api_url):
  16. self.api_url = api_url
  17.  
  18. def get_sports_data(self):
  19. response = requests.get(self.api_url)
  20. data = response.json()
  21.  
  22. sports_data = []
  23. for sport in data['sports']:
  24. if 'strSportThumb' in sport:
  25. sports_data.append(sport)
  26.  
  27. sports_data.sort(key=lambda x: x['strSport'])
  28. return sports_data
  29. #endregion
  30.  
  31. #region Define a class that extends the WindowXML class from the Kodi framework
  32. class AllSportsWindow(xbmcgui.WindowXML):
  33. API_URL = "https://www.thesportsdb.com/api/v1/json/60130162/all_sports.php"
  34.  
  35. def __init__(self, *args, **kwargs):
  36. # Call the parent class's constructor
  37. xbmcgui.WindowXML.__init__(self, *args, **kwargs)
  38.  
  39. # Set the path to the custom font and the font size
  40. self.font_path = "special://home/addons/plugin.sportsview/resources/fonts/ariblk.ttf"
  41. self.font_size = 40
  42. # Set the line spacing between words
  43. self.line_spacing = 1
  44.  
  45. def onInit(self):
  46. xbmc.log("AllSportsWindow - onInit")
  47.  
  48. # Retrieve sports data from an API
  49. sports_data = self.getSportsData()
  50.  
  51. # Populate the sports grid with the retrieved data
  52. self.populate_sports_grid(sports_data)
  53.  
  54. def tempPath(self):
  55. # Get the temporary path in the Kodi file system
  56. return xbmcvfs.translatePath("special://temp")
  57.  
  58. def getSportsData(self):
  59. sports_api = SportsAPI(self.API_URL)
  60. return sports_api.get_sports_data()
  61.  
  62. def populate_sports_grid(self, sports_data):
  63. # Define parameters for the sports grid layout
  64. numcolumns = 4
  65. vertgapsize = 50
  66. horizgapsize = 50
  67. totalgapsize = vertgapsize * (numcolumns + 1)
  68. screenwidth = self.getWidth()
  69. buttonwidth = (screenwidth - totalgapsize) // numcolumns
  70. buttonheight = int(buttonwidth / 1.7777777777777)
  71.  
  72. # Load the custom font
  73. font = ImageFont.truetype(self.font_path, self.font_size)
  74.  
  75. # Iterate through the sports data and create controls for each sport
  76. for index, sport in enumerate(sports_data):
  77. # Retrieve the sport label and image URL
  78. button_label = sport['strSport']
  79. button_image = sport['strSportThumb']
  80.  
  81. # Set self.sports_data to the populated sports_data list
  82. self.sports_data = sports_data
  83.  
  84. # Calculate the position of the control
  85. button_x = vertgapsize + (index % numcolumns) * (buttonwidth + vertgapsize)
  86. button_y = horizgapsize + (index // numcolumns) * (buttonheight + horizgapsize)
  87.  
  88. # Create an image control for the sport thumbnail
  89. image = xbmcgui.ControlImage(button_x, button_y, buttonwidth, buttonheight, filename=button_image)
  90. self.addControl(image)
  91.  
  92. # Download the unfocused button image
  93. response = requests.get(button_image)
  94. unfocused_image = Image.open(BytesIO(response.content))
  95.  
  96. # Convert the unfocused button image to grayscale
  97. focused_image_gray = ImageOps.grayscale(unfocused_image)
  98.  
  99. # Convert the grayscale image to RGB
  100. focused_image_rgb = focused_image_gray.convert('RGB')
  101.  
  102. # Set the border color as an RGB tuple
  103. border_color_rgb = (18, 101, 196) # Red color
  104.  
  105. # Set the width of the border
  106. border_width = 10 # Adjust as needed
  107.  
  108. # Create a new image with the colored border
  109. bordered_image = ImageOps.expand(focused_image_rgb, border=border_width, fill=border_color_rgb)
  110.  
  111. # Save the grayscale image to a temporary file
  112. focused_gray_path = os.path.join(self.tempPath(), f"focused_gray_{index}.png")
  113. focused_image_gray.save(focused_gray_path)
  114.  
  115. # Save the bordered image to a temporary file
  116. focused_texture_path = os.path.join(self.tempPath(), f"focused_image_{index}.png")
  117. bordered_image.save(focused_texture_path)
  118.  
  119. # Convert the border color tuple to a single integer value
  120. border_color_int = (0)
  121.  
  122. # Set the width of the border
  123. border_width = 10 # Adjust as needed
  124.  
  125. # Create a new image with the border
  126. bordered_image = ImageOps.expand(bordered_image, border=border_width, fill=border_color_int)
  127.  
  128. # Create an image control for the custom font button label
  129. label_image = Image.new("RGBA", (buttonwidth, buttonheight), (0, 0, 0, 0))
  130. label_draw = ImageDraw.Draw(label_image)
  131.  
  132. # Split the button label into individual words
  133. words = button_label.split()
  134.  
  135. # Join the words with line breaks
  136. label_text = '\n'.join(words)
  137.  
  138. # Split the label text into lines
  139. lines = label_text.split('\n')
  140.  
  141. # Get the width and height of the text
  142. text_width, text_height = label_draw.textsize(label_text, font=font)
  143.  
  144. # Calculate the button's y-axis to center align the text
  145. if len(lines) > 1:
  146. line_height = (buttonheight - text_height) // 2
  147. else:
  148. line_height = (buttonheight - text_height) // 2
  149.  
  150.  
  151. # Create a new image with the button label
  152. label_image = Image.new("RGBA", (buttonwidth, buttonheight), (0, 0, 0, 0))
  153. label_draw = ImageDraw.Draw(label_image)
  154.  
  155. # Draw the text on multiple lines
  156. for line in lines:
  157. # Calculate the button's x-axis to center align each line
  158. buttonx = (buttonwidth - label_draw.textsize(line, font=font)[0]) // 2
  159.  
  160. # Draw the line of text
  161. label_draw.text((buttonx, line_height), line, font=font, fill=(255, 255, 255, 255), anchor='mm')
  162.  
  163. # Increment the line height for the next line
  164. line_height += label_draw.textsize(line, font=font)[1] + self.line_spacing
  165.  
  166.  
  167. # Save the label image to a temporary file
  168. label_image_path = os.path.join(self.tempPath(), f"label_image_{index}.png")
  169. label_image.save(label_image_path)
  170.  
  171. # Create a button control for the sport
  172. button = xbmcgui.ControlButton(button_x, button_y, buttonwidth, buttonheight, label="", focusTexture=focused_texture_path)
  173. self.addControl(button)
  174.  
  175. # Store the control ID in the sports_data list
  176. sport['control_id'] = button.getId()
  177.  
  178. # Create an image control for the custom font button label
  179. label_image_control = xbmcgui.ControlImage(button_x, button_y, buttonwidth, buttonheight, filename=label_image_path)
  180. self.addControl(label_image_control)
  181.  
  182. # Set focus on the first button control
  183. if index == 0:
  184. self.setFocus(button)
  185.  
  186. def onAction(self, action):
  187. # Handle keyboard events for navigation
  188. if action == xbmcgui.ACTION_MOVE_LEFT:
  189. self.moveFocus(-1, 0)
  190. elif action == xbmcgui.ACTION_MOVE_RIGHT:
  191. self.moveFocus(1, 0)
  192. elif action == xbmcgui.ACTION_MOVE_UP:
  193. self.moveFocus(0, -1)
  194. elif action == xbmcgui.ACTION_MOVE_DOWN:
  195. self.moveFocus(0, 1)
  196. else:
  197. # Handle other actions here
  198. pass
  199.  
  200. # Call the parent onAction method to handle other actions
  201. xbmcgui.WindowXML.onAction(self, action)
  202.  
  203. def moveFocus(self, x, y):
  204. # Get the current focused button
  205. focused_control_id = self.getFocusId()
  206.  
  207. # Find the index of the focused control in the controls list
  208. focused_index = None
  209. for index, sport in enumerate(self.sports_data):
  210. if 'control_id' in sport and sport['control_id'] == focused_control_id:
  211. focused_index = index
  212. break
  213.  
  214. if focused_index is None:
  215. # Focused button not found or control_id not present, return
  216. return
  217.  
  218. # Calculate the new index after navigation
  219. num_columns = 4
  220. num_rows = (len(self.sports_data) - 1) // num_columns + 1
  221. new_index = focused_index + x + y * num_columns
  222.  
  223. # Check if the new index is within the range of buttons
  224. if 0 <= new_index < len(self.sports_data):
  225. # Get the control_id of the new button based on the new index
  226. new_control_id = self.sports_data[new_index].get('control_id')
  227.  
  228. if new_control_id is not None:
  229. # Set the focus on the new button control
  230. self.setFocusId(new_control_id)
  231.  
  232. # Check if the new button is off the visible screen area
  233. visible_index = focused_index // num_columns
  234. new_visible_index = new_index // num_columns
  235. if new_visible_index != visible_index:
  236. # Calculate the vertical scroll position
  237. scroll_position = self.getScrollPosition()[1]
  238. max_scroll = num_rows - self.getHeight() // self.getListItemHeight()
  239. new_scroll_position = min(max(scroll_position + y, 0), max_scroll) * self.getListItemHeight()
  240.  
  241. # Set the new vertical scroll position
  242. self.setScrollPosition(0, new_scroll_position)
  243. else:
  244. # New index is out of range, return
  245. return
  246.  
  247. # Call the parent onAction method to handle other actions
  248. super().onAction(xbmcgui.Action(self.getFocusId()))
  249.  
  250. #region Run it
  251. # Entry point function to run the AllSportsWindow
  252. def allsportsrun():
  253. # Get the current working directory of the add-on
  254. cwd = xbmcaddon.Addon().getAddonInfo('path')
  255.  
  256. # Create an instance of the AllSportsWindow and run it
  257. window = AllSportsWindow('allsports.xml', cwd, 'default', '1080i')
  258. window.doModal()
  259. del window
  260. #endregion
  261.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement