Files
Newsfeed---Mobile/newsfeed.py
2026-02-05 11:07:42 -05:00

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={"&#x27;","&#187;"}
for code in codes:
strItem=strItem.replace(code,"'")
strItem=strItem.replace("&amp;","&")
strItem=strItem.replace("&#x2018;","'")
strItem=strItem.replace("&#x2019;","'")
strItem=strItem.replace("&#x2014;","-")
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()