359 lines
11 KiB
Python
359 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("???","'")
|
|
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()
|