361 lines
11 KiB
Python
361 lines
11 KiB
Python
import tkinter as tk
|
||
import math
|
||
from functools import partial
|
||
import json
|
||
import webbrowser
|
||
import os
|
||
import requests
|
||
import traceback
|
||
import time
|
||
import glob
|
||
import re
|
||
import shutil
|
||
from datetime import timedelta
|
||
from datetime import datetime
|
||
from datetime import timezone
|
||
from environment import *
|
||
from utility import *
|
||
|
||
class Video:
|
||
def __init__(self):
|
||
self.description=None
|
||
self.url=None
|
||
self.icon=None
|
||
self.timestamp=DateTime()
|
||
self.feedTimeOffset='just now'
|
||
|
||
def __init__(self, description, url):
|
||
self.description=description
|
||
self.url=url
|
||
self.icon=None
|
||
self.timestamp=DateTime()
|
||
self.feedTimeOffset='just now'
|
||
|
||
def __init__(self, description, url, icon, timestamp=None):
|
||
self.description=description
|
||
self.url=url
|
||
self.icon=icon
|
||
if None==timestamp:
|
||
self.timestamp=DateTime()
|
||
else:
|
||
self.timestamp=timestamp
|
||
self.feedTimeOffset='just now'
|
||
|
||
def getDescription(self):
|
||
return self.description
|
||
|
||
def getUrl(self):
|
||
return self.url
|
||
|
||
def getIcon(self):
|
||
return self.icon
|
||
|
||
def getTimestamp(self):
|
||
return self.timestamp
|
||
|
||
def setFeedTime(self,feedtime):
|
||
self.feedtime=feedtime
|
||
|
||
def getFeedTime(self):
|
||
return self.feedtime
|
||
|
||
def getFeedTimeOffset(self):
|
||
return self.feedTimeOffset
|
||
|
||
def setFeedTimeOffset(self, feedtimeoffset):
|
||
self.feedTimeOffset=feedtimeoffset
|
||
|
||
def toString(self):
|
||
return(self.description+"|"+self.url+"|"+self.icon+"|"+self.timestamp.toString())
|
||
|
||
@staticmethod
|
||
def fromString(line):
|
||
splits=line.split("|")
|
||
description=splits[0].strip()
|
||
url=splits[1].strip()
|
||
icon=splits[2].strip()
|
||
timestamp=DateTime(splits[3].strip())
|
||
return(Video(description,url,icon,timestamp))
|
||
|
||
class NewsFeed:
|
||
def __init__(self, logger=None):
|
||
self.logger=logger
|
||
|
||
@staticmethod
|
||
def isResourceAvailable(url):
|
||
try:
|
||
response=requests.head(url, timeout=2.5)
|
||
if not response.ok:
|
||
return False
|
||
return True
|
||
except:
|
||
return False
|
||
|
||
def getItemsInFeed(self,url):
|
||
now=datetime.now()
|
||
sections=Sections()
|
||
videos = {}
|
||
httpNetRequest=HttpNetRequest()
|
||
response=httpNetRequest=httpNetRequest.getHttpNetRequest(url)
|
||
status=response.status_code
|
||
searchIndex=0
|
||
response.close()
|
||
if status!=200:
|
||
return None
|
||
while -1!= searchIndex:
|
||
video, searchIndex= sections.getItemsInSection(response.text,"article",searchIndex)
|
||
if video is not None and not (video.description in videos):
|
||
videos[video.description]=video
|
||
video.setFeedTime(DateTimeHelper.applyRelativeTime(now,video.feedTimeOffset))
|
||
videoList=NewsFeed.filterFeedMaxDays(list(videos.values()),7)
|
||
# videoList=list(videos.values())
|
||
videoList=sorted(videoList, key=lambda x:x.getFeedTime(),reverse=True)
|
||
return (videoList)
|
||
|
||
@staticmethod
|
||
def filterFeedMaxDays(videos,days):
|
||
now=datetime.now()
|
||
filteredList=[]
|
||
for video in videos:
|
||
delta=now-video.getFeedTime()
|
||
if delta.days <= days:
|
||
filteredList.insert(0,video)
|
||
return filteredList
|
||
|
||
class Sections:
|
||
def __init__(self):
|
||
self.dummy=None
|
||
|
||
def getItemsInSection(self, strInput, sectionName, searchIndex):
|
||
video=None
|
||
startSection='<'+sectionName
|
||
endSection='</'+sectionName
|
||
|
||
startIndex=strInput.find(startSection,searchIndex)
|
||
if -1 == startIndex:
|
||
searchIndex=-1
|
||
return video, searchIndex
|
||
|
||
endIndex=strInput.find(endSection,startIndex)
|
||
if -1 == endIndex:
|
||
searchIndex=-1
|
||
return video, searchIndex
|
||
|
||
searchIndex=endIndex+len(endSection)
|
||
strContainingString=strInput[startIndex:endIndex+1+len(endSection)]
|
||
|
||
if not strContainingString or strContainingString=="":
|
||
return video, searchIndex
|
||
|
||
indexPreview=strContainingString.find("preview=\"")
|
||
if -1 == indexPreview:
|
||
return video, searchIndex
|
||
previewUrl=strContainingString[indexPreview:]
|
||
previewUrl=self.betweenString(previewUrl,'"','"')
|
||
if "tokenvod" in previewUrl:
|
||
return video, searchIndex
|
||
|
||
indexDescription=strContainingString.index("alt=\"")
|
||
description=strContainingString[indexDescription:]
|
||
description=self.betweenString(description,'"','"')
|
||
description=self.removeHtml(description)
|
||
description=description.replace("- Fox News","")
|
||
if "vod.foxbusiness" in description:
|
||
return video, searchIndex
|
||
indexDuration=strContainingString.index("<div class=\"duration\">")
|
||
if -1 != indexDuration:
|
||
strDuration=strContainingString[indexDuration:]
|
||
strDuration=self.betweenString(strDuration,">","<")
|
||
description=description+" - "+strDuration
|
||
indexPublication=strContainingString.index("<div class=\"pub-date\">")
|
||
if -1 != indexPublication:
|
||
strPublication=strContainingString[indexPublication:]
|
||
strPublication=self.betweenString(strPublication,"<time>","</time>")
|
||
description=description+" ("+strPublication+")"
|
||
icon=None
|
||
indexIcon=strContainingString.index("srcset=")
|
||
if -1 != indexIcon:
|
||
icon=strContainingString[indexIcon:]
|
||
icon=self.betweenString(icon,"\"","\"")
|
||
splits=icon.split(',')
|
||
icon=self.betweenString(splits[len(splits)-1],None,'?')
|
||
icon=icon.strip()
|
||
video=Video(description,previewUrl,icon)
|
||
video.feedTimeOffset=strPublication
|
||
return video, searchIndex
|
||
|
||
def getVideoIdInSection(self, strInput, sectionName, searchIndex):
|
||
video=None
|
||
startSection='<'+sectionName
|
||
endSection='</'+sectionName
|
||
|
||
startIndex=strInput.find(startSection,searchIndex)
|
||
if -1 == startIndex:
|
||
searchIndex=-1
|
||
return video, searchIndex
|
||
|
||
endIndex=strInput.find(endSection,startIndex)
|
||
if -1 == endIndex:
|
||
searchIndex=-1
|
||
return video, searchIndex
|
||
|
||
searchIndex=endIndex+len(endSection)
|
||
strContainingString=strInput[startIndex:endIndex+1+len(endSection)]
|
||
if not strContainingString or strContainingString=="":
|
||
return video, searchIndex
|
||
indexVideoId=strContainingString.find("data-video-id")
|
||
if -1 ==indexVideoId:
|
||
return video, searchIndex
|
||
videoId=strContainingString[indexVideoId:]
|
||
videoId=self.betweenString(videoId,"\"","\"")
|
||
return videoId, searchIndex
|
||
|
||
def getVideoContentInSection(self, strInput):
|
||
video=None
|
||
searchItem="\"contentUrl\":"
|
||
indexContentUrl=strInput.find(searchItem)
|
||
if -1 == indexContentUrl:
|
||
return None
|
||
strContentUrl=strInput[indexContentUrl+len(searchItem):]
|
||
strContentUrl=self.betweenString(strContentUrl,"\"","\"")
|
||
strContentUrl=strContentUrl.strip()
|
||
|
||
searchItem="\"description\":"
|
||
indexDescription=strInput.find(searchItem)
|
||
if -1 == indexDescription:
|
||
return None
|
||
strDescription=strInput[indexDescription+len(searchItem):]
|
||
strDescription=self.betweenString(strDescription,"\"","\"")
|
||
strDescription=strDescription.strip()
|
||
|
||
searchItem="\"thumbnailUrl\":"
|
||
indexIcon=strInput.find(searchItem)
|
||
if -1 == indexIcon:
|
||
return None
|
||
strIcon=strInput[indexIcon+len(searchItem):]
|
||
strIcon=self.betweenString(strIcon,"\"","\"")
|
||
strIcon=strIcon.strip()
|
||
|
||
searchItem="\"duration\""
|
||
indexDuration=strInput.find(searchItem)
|
||
if -1 != indexDuration:
|
||
strDuration=strInput[indexDuration+len(searchItem):]
|
||
strDuration=self.betweenString(strDuration,"\"","\"")
|
||
strDuration=strDuration.strip()
|
||
minutes, seconds = parseDuration(strDuration)
|
||
if None!=minutes and None!=seconds:
|
||
strDescription=strDescription+" - "+minutes+":"+seconds
|
||
video=Video(strDescription,strContentUrl,strIcon)
|
||
return video
|
||
|
||
def betweenString(self, strItem, strBegin, strEnd ):
|
||
return StringHelper.betweenString(strItem, strBegin, strEnd)
|
||
|
||
def removeHtml(self,strItem):
|
||
if strItem is None:
|
||
return None
|
||
codes={"'","»"}
|
||
for code in codes:
|
||
strItem=strItem.replace(code,"'")
|
||
strItem=strItem.replace("&","&")
|
||
strItem=strItem.replace("‘","‘")
|
||
strItem=strItem.replace("’","’")
|
||
strItem=strItem.replace("—","-")
|
||
strItem=strItem.replace("'","'")
|
||
strItem=strItem.replace("???","'")
|
||
strItem=strItem.replace(""","\"")
|
||
return strItem
|
||
|
||
def pad(str,filler,length):
|
||
stringLength=len(str)
|
||
sb=""
|
||
if stringLength>=length:
|
||
return str
|
||
while stringLength < length:
|
||
sb=sb+filler
|
||
stringLength=stringLength+1
|
||
return sb+str
|
||
|
||
def parseDuration(strDuration):
|
||
expression=re.compile(r"\d+")
|
||
result=expression.findall(strDuration)
|
||
if 2!=len(result):
|
||
return None, None
|
||
return pad(result[0],'0',2), pad(result[1],'0',2)
|
||
|
||
|
||
def selectedItem(event):
|
||
widget=event.widget
|
||
selectedIndex=int(widget.curselection()[0])
|
||
itemsInList=len(videoCollection.getVideoList())
|
||
if selectedIndex >=0 and selectedIndex < itemsInList:
|
||
videoUrl=videoCollection.getVideoList()[selectedIndex].getUrl()
|
||
webbrowser.open(videoUrl)
|
||
|
||
def refresh():
|
||
listbox.delete(0,'end')
|
||
loadVideos()
|
||
|
||
def loadVideos():
|
||
newsfeed=NewsFeed()
|
||
videos=newsfeed.getItemsInFeed(FOX_NEWS_URL)
|
||
itemIndex=1
|
||
for video in videos:
|
||
listbox.insert(itemIndex,video.getDescription())
|
||
itemIndex=itemIndex+1
|
||
videoCollection.setVideoList(videos)
|
||
|
||
class VideoCollection:
|
||
def __init__(self):
|
||
self.videoList=[]
|
||
|
||
def getVideoList(self):
|
||
return self.videoList
|
||
|
||
def setVideoList(self,videoList):
|
||
self.videoList=videoList
|
||
|
||
videoCollection=VideoCollection()
|
||
|
||
master = tk.Tk()
|
||
master.geometry("450x300")
|
||
#master.geometry("640x480")
|
||
|
||
#Frame
|
||
frame=tk.Frame(master,height=100)
|
||
frame.pack(fill='both',expand='true')
|
||
|
||
bottomframe=tk.Frame()
|
||
bottomframe.pack(side='bottom')
|
||
|
||
#Entry
|
||
label_heading = tk.Label(frame, text = "Fox News Video Feed",font='arial 13 bold',background='blue',foreground='white')
|
||
label_heading.pack(side='top', fill='both')
|
||
|
||
#yscrollbar for list
|
||
yscrollbar=tk.Scrollbar(frame)
|
||
yscrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||
|
||
#xscrollbar for list
|
||
xscrollbar=tk.Scrollbar(frame, orient=tk.HORIZONTAL)
|
||
xscrollbar.pack(side=tk.BOTTOM,fill=tk.X)
|
||
|
||
# List
|
||
listbox=tk.Listbox(frame,selectmode='single',yscrollcommand=yscrollbar.set,xscrollcommand=xscrollbar.set)
|
||
listbox.pack(side='left', fill='both')
|
||
listbox.bind('<Double-Button>',selectedItem)
|
||
listbox.configure(background='skyblue4',foreground='white',font='arial 8 bold',width=0)
|
||
|
||
#configure the scrollbar
|
||
yscrollbar.config(command=listbox.yview)
|
||
xscrollbar.config(command=listbox.xview)
|
||
|
||
#Button
|
||
btn_refresh = tk.Button(bottomframe,text = 'Refresh',command = refresh)
|
||
btn_refresh.pack(side='bottom')
|
||
|
||
loadVideos()
|
||
listbox.focus_set()
|
||
|
||
master.mainloop()
|