From 9d166d8b4297956dc2d72cc1dfa10af91e6f945f Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Tue, 7 Dec 2021 09:51:53 +0100 Subject: [PATCH] Can play video from SVT --- ChannelProvider/SVT/__init__.py | 49 ++++++++++++++++++++ ChannelProvider/YouTube/__init__.py | 0 ChannelProvider/__init__.py | 24 ++++++++++ Items/__init__.py | 66 +++++++++++++++++++++++++++ dpkg.lst | 26 +++++++++++ main.py | 70 +++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+) create mode 100644 ChannelProvider/SVT/__init__.py create mode 100644 ChannelProvider/YouTube/__init__.py create mode 100644 ChannelProvider/__init__.py create mode 100644 Items/__init__.py create mode 100644 dpkg.lst create mode 100644 main.py diff --git a/ChannelProvider/SVT/__init__.py b/ChannelProvider/SVT/__init__.py new file mode 100644 index 0000000..bd71c8d --- /dev/null +++ b/ChannelProvider/SVT/__init__.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import ChannelProvider +import feedparser +import requests +from bs4 import BeautifulSoup +from Items import Item +import json + + +class SVT(ChannelProvider.ChannelProvider): + def __init__(self) -> None: + super().__init__('SVT', 'http://www.svtplay.se/rss.xml') + + def parse_feed(self) -> list[Item]: + feed = feedparser.parse(self.get_feed()) + entries = feed['entries'] + items: list[Item] = list() + + for entry in entries: + thumbnail = '' + svt_id = '' + for link in entry['links']: + if str(link['type']).startswith('image/'): + thumbnail = str(link['href']) + page = requests.get(str(entry['link'])) + soup = BeautifulSoup(page.text, 'html.parser') + + for element in soup.find_all('a'): + href = element.get('href') + datart= element.get('data-rt') + + if datart == 'top-area-play-button': + svt_id = href.split('=')[1].split('&')[0] + + api = json.loads(requests.get('https://api.svt.se/video/{}'.format(svt_id)).text) + #print(api['videoReferences']) + resolved_link = '' + for reference in api['videoReferences']: + if reference['format'] == "dashhbbtv": + resolved_link = reference['url'] + print(resolved_link) + + item = Item(str(entry['description']), resolved_link, + self.m_provider_name, entry['published_parsed'], + thumbnail, str(entry['title'])) + items.append(item) + + return items diff --git a/ChannelProvider/YouTube/__init__.py b/ChannelProvider/YouTube/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ChannelProvider/__init__.py b/ChannelProvider/__init__.py new file mode 100644 index 0000000..3964a29 --- /dev/null +++ b/ChannelProvider/__init__.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +from typing import Union + +from Items import Item + + +class ChannelProvider: + def __init__(self, provider_name: str, feed: str) -> None: + self.m_provider_name = provider_name + self.m_feed = feed + self.m_items: Union[list[Item], None] = self.parse_feed() + + def get_feed(self) -> str: + return self.m_feed + + def get_items(self) -> Union[list[Item], None]: + return self.m_items + + def get_provider_name(self) -> str: + return self.m_provider_name + + def parse_feed(self) -> Union[list[Item], None]: + pass diff --git a/Items/__init__.py b/Items/__init__.py new file mode 100644 index 0000000..39ca682 --- /dev/null +++ b/Items/__init__.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +from datetime import datetime + + +class Item(dict): + def __init__(self, + description: str, + link: str, + provider_id: str, + published: datetime, + thumbnail: str, + title: str, + watchtime: int = 0): + self.__dict__['description'] = description + self.__dict__['link'] = link + self.__dict__['provider_id'] = provider_id + self.__dict__['published'] = published + self.__dict__['thumbnail'] = thumbnail + self.__dict__['title'] = title + self.__dict__['watchtime'] = watchtime + + def __setitem__(self, key, item): + self.__dict__[key] = item + + def __getitem__(self, key): + return self.__dict__[key] + + def __repr__(self): + return repr(self.__dict__) + + def __delitem__(self, key): + del self.__dict__[key] + + def clear(self): + return self.__dict__.clear() + + def copy(self): + return self.__dict__.copy() + + def has_key(self, k): + return k in self.__dict__ + + def update(self, *args, **kwargs): + return self.__dict__.update(*args, **kwargs) + + def keys(self): + return self.__dict__.keys() + + def values(self): + return self.__dict__.values() + + def items(self): + return self.__dict__.items() + + def pop(self, *args): + return self.__dict__.pop(*args) + + def __cmp__(self, dict_): + return self.__dict__ == dict_ + + def __contains__(self, item): + return item in self.__dict__ + + def __iter__(self): + return iter(self.__dict__) diff --git a/dpkg.lst b/dpkg.lst new file mode 100644 index 0000000..73a0803 --- /dev/null +++ b/dpkg.lst @@ -0,0 +1,26 @@ +gir1.2-gstreamer-1.0:amd64 +gstreamer1.0-alsa:amd64 +gstreamer1.0-clutter-3.0:amd64 +gstreamer1.0-gl:amd64 +gstreamer1.0-gtk3:amd64 +gstreamer1.0-libav:amd64 +gstreamer1.0-nice:amd64 +gstreamer1.0-packagekit +gstreamer1.0-pipewire:amd64 +gstreamer1.0-plugins-bad:amd64 +gstreamer1.0-plugins-base:amd64 +gstreamer1.0-plugins-base-apps +gstreamer1.0-plugins-good:amd64 +gstreamer1.0-plugins-rtp +gstreamer1.0-plugins-ugly:amd64 +gstreamer1.0-pulseaudio:amd64 +gstreamer1.0-tools +gstreamer1.0-x:amd64 +libgstreamer-gl1.0-0:amd64 +libgstreamer-plugins-bad1.0-0:amd64 +libgstreamer-plugins-base1.0-0:amd64 +libgstreamer-plugins-good1.0-0:amd64 +libgstreamer1.0-0:amd64 +python3-wxgtk-media4.0 +python3-wxgtk4.0 +python3-feedparser diff --git a/main.py b/main.py new file mode 100644 index 0000000..e6a8ac0 --- /dev/null +++ b/main.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +import hashlib +from typing import NewType + +import wx +import wx.media + +from ChannelProvider import SVT, ChannelProvider + +ChannelProvider = NewType('ChannelProvider', ChannelProvider) + + +class Cast(wx.Frame): + m_channels: list[ChannelProvider] = list() + + def __init__(self, *args, **kw): + """__init__. + :param args: + :param kw: + """ + super().__init__(*args, **kw) + self.m_channels.append(SVT.SVT()) + self.m_control = wx.media.MediaCtrl( + self, + size=(480, 480), + style=wx.SIMPLE_BORDER, + szBackend=wx.media.MEDIABACKEND_GSTREAMER) + play_button = wx.Button(self, -1, "Play") + self.Bind(wx.EVT_BUTTON, self.play, play_button) + + pause_button = wx.Button(self, -1, "Pause") + self.Bind(wx.EVT_BUTTON, self.pause, pause_button) + + stop_button = wx.Button(self, -1, "Stop") + self.Bind(wx.EVT_BUTTON, self.quit, stop_button) + + sizer = wx.GridBagSizer() + sizer.Add(self.m_control, (0, 0)) + sizer.SetItemSpan(0, (0, 6)) + sizer.Add(play_button, (1, 1)) + sizer.Add(pause_button, (1, 2)) + sizer.Add(stop_button, (1, 3)) + self.SetSizer(sizer) + + self.m_control.Bind(wx.media.EVT_MEDIA_LOADED, self.play) + self.m_control.Bind(wx.media.EVT_MEDIA_FINISHED, self.quit) + self.load_video(self.m_channels[0].get_items()[0]['link']) + self.Show(True) + sizer.Layout() + + def load_video(self, uri): + self.m_control.LoadURI(uri) + + def play(self, event): + self.m_control.Play() + + def pause(self, event): + self.m_control.Pause() + + def quit(self, event): + self.Destroy() + + +if __name__ == '__main__': + # When this module is run (not imported) then create the app, the + # frame, show it, and start the event loop. + app: wx.App = wx.App() + frm: Cast = Cast(None, title='Cast') + frm.Show() + app.MainLoop()