Super Skin but the problem is that in Poland rss feeds in 98% look like this:
http://www.tvn24.pl/najnowsze.xml
http://dobreprogramy.pl/rss/rss_progs.xml
http://rss.gazeta.pl/pub/rss/sport.xml
Is it possible to open it with the tip of xml feeds?
It is currently June 10th, 2023, 7:10 pm
FeedReader w/ sorting
-
- Posts: 112
- Joined: August 18th, 2012, 5:19 pm
-
- Posts: 1120
- Joined: January 22nd, 2011, 4:23 pm
- Location: GMT +8
Re: FeedReader w/ sorting
Sorry about that. The reader was primarily intended to sort the BBC and Guardian news feeds and couldn't cope with publication dates in the <pubDate>Tue, 11 Sep 12 07:06:00 +0200</pubDate> format. I've done a gutter-tape and monkey-wrench job on the script and the updated version posted on Deviant Art will handle feeds like those you mentioned.
However, I didn't try to make it work with all time and date formats as Kaleri's latest reader script does a much better job and is more reliable across a wider range of feed types.
However, I didn't try to make it work with all time and date formats as Kaleri's latest reader script does a much better job and is more reliable across a wider range of feed types.
-
- Posts: 112
- Joined: August 18th, 2012, 5:19 pm
Re: FeedReader w/ sorting
Once again, a big, very big thanks! This time here on the forum! It works with XML! 

-
- Posts: 21
- Joined: May 9th, 2012, 10:11 am
Re: FeedReader w/ sorting
What about this RSS:
http://stackoverflow.com/feeds
http://serverfault.com/feeds
http://superuser.com/feeds
http://unix.stackexchange.com/feeds
http://feeds.feedburner.com/niebezpiecznik/
http://freecode.com/?format=atom
http://rss.slashdot.org/Slashdot/slashdotLinux
http://bsdtalk.blogspot.com/feeds/posts/default
http://lcamtuf.blogspot.com/feeds/posts/default?alt=rss
They doesn't work. Is there a possibility to correct this ?
And another problem:
When you switch from feed where there is 10 feeds to another feed where is less than 10 feeds, there is some problem with refresh.
I get e.g. 5 feeds from current set of feeds and another 5 from recently read feeds when i switch to another one. IMHO there should be visible only 5 current feeds instead of 10.
http://stackoverflow.com/feeds
http://serverfault.com/feeds
http://superuser.com/feeds
http://unix.stackexchange.com/feeds
http://feeds.feedburner.com/niebezpiecznik/
http://freecode.com/?format=atom
http://rss.slashdot.org/Slashdot/slashdotLinux
http://bsdtalk.blogspot.com/feeds/posts/default
http://lcamtuf.blogspot.com/feeds/posts/default?alt=rss
They doesn't work. Is there a possibility to correct this ?
And another problem:
When you switch from feed where there is 10 feeds to another feed where is less than 10 feeds, there is some problem with refresh.
I get e.g. 5 feeds from current set of feeds and another 5 from recently read feeds when i switch to another one. IMHO there should be visible only 5 current feeds instead of 10.
-
- Posts: 1120
- Joined: January 22nd, 2011, 4:23 pm
- Location: GMT +8
Re: FeedReader w/ sorting
The easiest way to correct this will be to use Kaleri's latest reader script but I haven't got around to adapting it to show the bulleting of recent feeds yet. It shouldn't be that difficult as Kaleri's script already handles various timestamp formats and puts the publication dates into tables where they can be easily sorted.rainusero wrote:They doesn't work. Is there a possibility to correct this ?
-
- Posts: 21
- Joined: May 9th, 2012, 10:11 am
Re: FeedReader w/ sorting
Dear Mordasius,
1. Will you be able to fully (or almost fully) adapt Kaleri's script to your skin to handle various ATOM/RSS formats ?
2. Another sample RSS that doesn't work (shows Empty. on RSS list): http://dozzie.jarowit.net/usenix-login.xml. Could you check in ?
3. Refresh problem
When you switch from feed where there is 10 feeds to another feed where is less than 10 feeds, there is some problem with refresh.
I get e.g. 5 feeds from current set of feeds and another 5 from recently read feeds when I switch to another one. IMHO there should be visible only 5 current feeds instead of 10.
4. Last but not least. If there is an issue when some RSS/ATOM doesn't work (like this: http://storagedevicessafety.info/feed/) a message is shown: "Matching Error. No valid feed found". That's okay and quite normal behavior. But there is one case (I found only one case - perhaps there is more than one) where above rule doesn't apply.
Here it is: http://www.linux.com/rss/feeds.php. There is something wrong with this feed. If you type it in your browser address bar you'll get redirection to another address: http://archive09.linux.com/rss/feeds.php. Something doesn't work. It's obvious but this is not our fault and it's not so important
Significant is that instead of message, I mentioned above (Matching error, etc...), entire rainmeter is hanging up. I must open process manager, kill rainmeter.exe process, then open my feed list, delete "invalid" entry (http://www.linux.com/rss/feeds.php in this case), restart application and after that everything works fine. IMHO this is not usual and proper behavior and should be immediately corrected. Displaying a message "Matching Error. No valid feed found" in every case when there's something wrong with RSS should be good enough. Without hanging up entire application.
It is very inconvenient and annoying to watch all the time if some RSS/ATOM is broken in this way, isn't it ? Please check your lua script for that "contingency". This time it was only one feed but in near future... who knows.
I wonder, I'm just only one person with this issue...
1. Will you be able to fully (or almost fully) adapt Kaleri's script to your skin to handle various ATOM/RSS formats ?
2. Another sample RSS that doesn't work (shows Empty. on RSS list): http://dozzie.jarowit.net/usenix-login.xml. Could you check in ?
3. Refresh problem
When you switch from feed where there is 10 feeds to another feed where is less than 10 feeds, there is some problem with refresh.
I get e.g. 5 feeds from current set of feeds and another 5 from recently read feeds when I switch to another one. IMHO there should be visible only 5 current feeds instead of 10.
4. Last but not least. If there is an issue when some RSS/ATOM doesn't work (like this: http://storagedevicessafety.info/feed/) a message is shown: "Matching Error. No valid feed found". That's okay and quite normal behavior. But there is one case (I found only one case - perhaps there is more than one) where above rule doesn't apply.
Here it is: http://www.linux.com/rss/feeds.php. There is something wrong with this feed. If you type it in your browser address bar you'll get redirection to another address: http://archive09.linux.com/rss/feeds.php. Something doesn't work. It's obvious but this is not our fault and it's not so important

Significant is that instead of message, I mentioned above (Matching error, etc...), entire rainmeter is hanging up. I must open process manager, kill rainmeter.exe process, then open my feed list, delete "invalid" entry (http://www.linux.com/rss/feeds.php in this case), restart application and after that everything works fine. IMHO this is not usual and proper behavior and should be immediately corrected. Displaying a message "Matching Error. No valid feed found" in every case when there's something wrong with RSS should be good enough. Without hanging up entire application.
It is very inconvenient and annoying to watch all the time if some RSS/ATOM is broken in this way, isn't it ? Please check your lua script for that "contingency". This time it was only one feed but in near future... who knows.
I wonder, I'm just only one person with this issue...
-
- Posts: 1120
- Joined: January 22nd, 2011, 4:23 pm
- Location: GMT +8
Re: FeedReader w/ sorting
Thanks for reporting the bugs. All of the problems you mention above were caused by the way the Lua script was handling different date formats. I'm sure there must have been other people with the same problems but they just haven't reported them.
I've now incorporated Kaleri's latest Reader script which seems to fix most, but not all, of the errors you mentioned. I just made a few changes to sort the feeds by date/time and 'bullet' those which are less than 30 minutes old (you can change the value). I've also trimmed the title of the Rainmeter Forums threads as in the original version of the FeedReader.
Download a new copy from Deviant Art and let me know if you find any more errors.
I've now incorporated Kaleri's latest Reader script which seems to fix most, but not all, of the errors you mentioned. I just made a few changes to sort the feeds by date/time and 'bullet' those which are less than 30 minutes old (you can change the value). I've also trimmed the title of the Rainmeter Forums threads as in the original version of the FeedReader.
Download a new copy from Deviant Art and let me know if you find any more errors.
-
- Posts: 21
- Joined: May 9th, 2012, 10:11 am
Re: FeedReader w/ sorting
Great work.
But where is possibility to increase number of feed channels to more than 5 and increase number of visible feeds to more than 9.
In your recent version there was a variable called NumberOfFeeds. Where is it now ?
Could you implement it again ?
Could you explain what does this part do ?
WebParserSubstitute="<![CDATA[":"","]]>":"","/PRE>":"","PRE>":""," ":" ","'s Facebook Notifications":"","Top Stories - Google ":""
But where is possibility to increase number of feed channels to more than 5 and increase number of visible feeds to more than 9.
In your recent version there was a variable called NumberOfFeeds. Where is it now ?
Could you implement it again ?
Could you explain what does this part do ?
WebParserSubstitute="<![CDATA[":"","]]>":"","/PRE>":"","PRE>":""," ":" ","'s Facebook Notifications":"","Top Stories - Google ":""
Last edited by rainusero on October 2nd, 2012, 2:32 pm, edited 1 time in total.
-
- Developer
- Posts: 1721
- Joined: July 25th, 2009, 4:47 am
Re: FeedReader w/ sorting
@Mordasius: Let me give you my most recent working copy of the Reader script. It's a little messy, but I tested it on each of the feeds above, and it seems to handle all the dates.
Code: Select all
function Initialize()
-- SET UPDATE DIVIDER
SKIN:Bang('!SetOption', SELF:GetName(), 'UpdateDivider', -1)
-- This script never needs to update on a schedule. It should only
-- update when it gets a "Refresh" command from WebParser.
-- CREATE MAIN DATABASE
Feeds = {}
-- CREATE TYPE MATCHING PATTERNS AND FORMATTING FUNCTIONS
DefineTypes()
-- GET MEASURE NAMES
local AllMeasureNames = SELF:GetOption('MeasureName', '')
for MeasureName in AllMeasureNames:gmatch('[^%|]+') do
table.insert(Feeds, {
Measure = SKIN:GetMeasure(MeasureName),
MeasureName = MeasureName,
Raw = nil,
Type = nil,
Title = nil,
Link = nil,
Error = nil
})
end
-- MODULES
EventFile_Initialize()
HistoryFile_Initialize()
-- SET STARTING FEED
f = f or 1
-- SET USER INPUT
UserInput = false
-- Used to detect when an item has been marked as read.
end
function Update()
Input()
return Output()
end
-----------------------------------------------------------------------
-- INPUT
function Input(a)
local f = a or f
local Raw = Feeds[f].Measure:GetStringValue()
if Raw == '' then
Feeds[f].Error = {
Description = 'Waiting for data from WebParser.',
Title = 'Loading...',
Link = 'http://enigma.kaelri.com/support'
}
return false
elseif (Raw ~= Feeds[f].Raw) or UserInput then
Feeds[f].Raw = Raw
-- DETERMINE FEED FORMAT AND CONTENTS
local t = IdentifyType(Raw)
if not t then
Feeds[f].Error = {
Description = 'Could not identify a valid feed format.',
Title = 'Invalid Feed Format',
Link = 'http://enigma.kaelri.com/support'
}
return false
else
Feeds[f].Type = t
end
-- MAKE SYNTAX PRETTIER
local Type = Types[t]
-- GET NEW DATA
Feeds[f].Title = Raw:match('<title.->(.-)</title>') or 'Untitled'
Feeds[f].Link = Raw:match(Type.MatchLink) or nil
local Items = {}
for RawItem in Raw:gmatch(Type.MatchItem) do
local Item = {}
-- MATCH RAW DATA
Item.Unread = 1
Item.Title = RawItem:match('<title.->(.-)</title>') or nil
Item.Link = RawItem:match(Type.MatchItemLink) or nil
Item.Desc = RawItem:match(Type.MatchItemDesc) or nil
Item.Date = RawItem:match(Type.MatchItemDate) or RawItem:match(Type.MatchItemDate2) or nil
Item.ID = RawItem:match(Type.MatchItemID) or Item.Link or Item.Title or Item.Desc or Item.Date
-- ADDITIONAL PARSING
if (not Item.Title) or (Item.Title == '') then
Item.Title = 'Untitled'
end
if Item.Desc then
Item.Desc = Item.Desc:gsub('<.->', '')
Item.Desc = Item.Desc:gsub('%s%s+', ' ')
end
Item.Date, Item.AllDay, Item.RealDate = IdentifyDate(Item.Date, t)
table.insert(Items, Item)
end
-- IDENTIFY DUPLICATES
for i, OldItem in ipairs(Feeds[f]) do
for j, NewItem in ipairs(Items) do
if NewItem.ID == OldItem.ID then
Feeds[f][i].Match = j
Items[j].Unread = OldItem.Unread
if NewItem.RealDate == 0 then
Items[j].Date = OldItem.Date
Items[j].AllDay = OldItem.AllDay
end
end
end
end
-- CLEAR DUPLICATES OR ALL HISTORY
local KeepOldItems = SELF:GetNumberOption('KeepOldItems', 0)
if (KeepOldItems == 1) and Type.MergeItems then
for i = #Feeds[f], 1, -1 do
if Feeds[f][i].Match then
table.remove(Feeds[f], i)
end
end
else
for i = 1, #Feeds[f] do
table.remove(Feeds[f])
end
end
-- ADD NEW ITEMS
for i = #Items, 1, -1 do
if Items[i] then
table.insert(Feeds[f], 1, Items[i])
end
end
-- CHECK NUMBER OF ITEMS
local MaxItems = SELF:GetNumberOption('MaxItems', nil)
local MaxItems = (MaxItems > 0) and MaxItems or nil
if #Feeds[f] == 0 then
Feeds[f].Error = {
Description = 'No items found.',
Title = Feeds[f]['Title'],
Link = Feeds[f]['Link']
}
return false
elseif MaxItems and (#Feeds[f] > MaxItems) then
for i = #Feeds[f], (MaxItems + 1), -1 do
table.remove(Feeds[f])
end
end
-- MODULES
EventFile_Update(f)
HistoryFile_Update(f)
-- CLEAR ERRORS FROM PREVIOUS UPDATE
Feeds[f].Error = nil
-- RESET USER INPUT
UserInput = false
end
return true
end
-----------------------------------------------------------------------
-- OUTPUT
function Output()
local Queue = {}
-- MAKE SYNTAX PRETTIER
local Feed = Feeds[f]
local Type = Types[Feed.Type]
local Error = Feed.Error
-- BUILD QUEUE
Queue['CurrentFeed'] = f
Queue['NumberOfItems'] = #Feed
-- CHECK FOR INPUT ERRORS
local MinItems = SELF:GetNumberOption('MinItems', 0)
local Timestamp = SELF:GetOption('Timestamp', '%I.%M %p on %d %B %Y')
if Error then
-- ERROR; QUEUE MESSAGES
Queue['FeedTitle'] = Error.Title
Queue['FeedLink'] = Error.Link
Queue['Item1Title'] = Error.Description
Queue['Item1Link'] = Error.Link
Queue['Item1Desc'] = ''
Queue['Item1Date'] = ''
Queue['Item1Unread'] = 0
for i = 2, MinItems do
Queue['Item'..i..'Title'] = ''
Queue['Item'..i..'Link'] = ''
Queue['Item'..i..'Desc'] = ''
Queue['Item'..i..'Date'] = ''
Queue['Item'..i..'Unread'] = 0
end
else
-- NO ERROR; QUEUE FEED
Queue['FeedTitle'] = Feed.Title
Queue['FeedLink'] = Feed.Link or ''
for i = 1, math.max(#Feed, MinItems) do
local Item = Feed[i] or {}
Queue['Item'..i..'Title'] = Item.Title or ''
Queue['Item'..i..'Link'] = Item.Link or Feed.Link or ''
Queue['Item'..i..'Desc'] = Item.Desc or ''
Queue['Item'..i..'Unread'] = Item.Unread or ''
Queue['Item'..i..'Date'] = Item.Date and os.date(Timestamp, Item.Date) or ''
end
end
-- SET VARIABLES
local VariablePrefix = SELF:GetOption('VariablePrefix', '')
for k, v in pairs(Queue) do
SKIN:Bang('!SetVariable', VariablePrefix..k, v)
end
-- FINISH ACTION
local FinishAction = SELF:GetOption('FinishAction', '')
if FinishAction ~= '' then
SKIN:Bang(FinishAction)
end
return Error and Error.Description or 'Finished #'..f..' ('..Feed.MeasureName..'). Name: '..Feed.Title..'. Type: '..Feed.Type..'. Items: '..#Feed..'.'
end
-----------------------------------------------------------------------
-- EXTERNAL COMMANDS
function Refresh(a)
a = a and tonumber(a) or f
if a == f then
SKIN:Bang('!UpdateMeasure', SELF:GetName())
else
Input(a)
end
end
function Show(a)
f = tonumber(a)
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
function ShowNext()
f = (f % #Feeds) + 1
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
function ShowPrevious()
f = (f == 1) and #Feeds or (f - 1)
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
function MarkRead(a, b)
b = b and tonumber(b) or f
Feeds[b][a].Unread = 0
UserInput = true
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
function MarkUnread(a, b)
b = b and tonumber(b) or f
Feeds[b][a].Unread = 1
UserInput = true
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
function ToggleUnread(a, b)
b = b and tonumber(b) or f
Feeds[b][a].Unread = 1 - Feeds[b][a].Unread
UserInput = true
SKIN:Bang('!UpdateMeasure', SELF:GetName())
end
-----------------------------------------------------------------------
-- TYPES
function DefineTypes()
Types = {
RSS = {
MatchLink = '<link.->(.-)</link>',
MatchItem = '<item.-</item>',
MatchItemID = '<guid.->(.-)</guid>',
MatchItemLink = '<link.->(.-)</link>',
MatchItemDesc = '<description.->(.-)</description>',
MatchItemDate = '<pubDate.->(.-)</pubDate>',
MatchItemDate2 = '<dc:date>(.-)</dc:date>',
MergeItems = true,
ParseDate = function(s)
print(s)
local Date = {}
local MatchTime = '%a+, (%d+) (%a+) (%d+) (%d+)%:(%d+)%:(%d+) (.-)$'
local MatchDate = '%a+, (%d+) (%a+) (%d+)$'
if s:match(MatchTime) then
Date.day, Date.month, Date.year, Date.hour, Date.min, Date.sec, Date.Offset = s:match(MatchTime)
elseif s:match(MatchDate) then
Date.day, Date.month, Date.year = s:match(MatchDate)
end
return (Date.year and Date.month and Date.day) and Date or nil
end
},
Atom = {
MatchLink = '<link.-href=["\'](.-)["\']',
MatchItem = '<entry.-</entry>',
MatchItemID = '<id.->(.-)</id>',
MatchItemLink = '<link.-href=["\'](.-)["\']',
MatchItemDesc = '<summary.->(.-)</summary>',
MatchItemDate = '<updated.->(.-)</updated>',
MergeItems = true,
ParseDate = function(s)
local Date = {}
local MatchTime = '(%d+)%-(%d+)%-(%d+)T(%d+)%:(%d+)%:(%d+)(.-)$'
local MatchDate = '(%d+)%-(%d+)%-(%d+)$'
if s:match(MatchTime) then
Date.year, Date.month, Date.day, Date.hour, Date.min, Date.sec, Date.Offset = s:match(MatchTime)
elseif s:match(MatchDate) then
Date.year, Date.month, Date.day = s:match(MatchDate)
end
return Date
end
},
GoogleCalendar = {
MatchLink = '<link.-rel=.-alternate.-href=["\'](.-)["\']',
MatchItem = '<entry.-</entry>',
MatchItemID = '<id.->(.-)</id>',
MatchItemLink = '<link.-href=["\'](.-)["\']',
MatchItemDesc = '<summary.->(.-)</summary>',
MatchItemDate = 'startTime=["\'](.-)["\']',
MergeItems = false,
ParseDate = function(s)
local Date = {}
local MatchTime = '(%d+)%-(%d+)%-(%d+)T(%d+)%:(%d+)%:(%d+)%.%d+(.-)$'
local MatchDate = '(%d+)%-(%d+)%-(%d+)$'
if s:match(MatchTime) then
Date.year, Date.month, Date.day, Date.hour, Date.min, Date.sec, Date.Offset = s:match(MatchTime)
elseif s:match(MatchDate) then
Date.year, Date.month, Date.day = s:match(MatchDate)
end
return Date
end
},
RememberTheMilk = {
MatchLink = '<link.-rel=.-alternate.-href=["\'](.-)["\']',
MatchItem = '<entry.-</entry>',
MatchItemID = '<id.->(.-)</id>',
MatchItemLink = '<link.-href=["\'](.-)["\']',
MatchItemDesc = '<summary.->(.-)</summary>',
MatchItemDate = '<span class=["\']rtm_due_value["\']>(.-)</span>',
MergeItems = false,
ParseDate = function(s)
local Date = {}
local MatchTime = '%a+ (%d+) (%a+) (%d+) at (%d+)%:(%d+)(%a+)' -- e.g. 'Wed 7 Nov 12 at 3:17PM'
local MatchDate = '%a+ (%d+) (%a+) (%d+)' -- e.g. 'Tue 25 Dec 12'
if s:match(MatchTime) then
Date.day, Date.month, Date.year, Date.hour, Date.min, Date.Meridiem = s:match(MatchTime)
elseif s:match(MatchDate) then
Date.day, Date.month, Date.year = s:match(MatchDate)
end
return Date
end
}
}
end
-------------------------
function IdentifyType(s)
-- COLLAPSE CONTAINER TAGS
for _, v in ipairs{ 'item', 'entry' } do
s = s:gsub('<'..v..'.->.+</'..v..'>', '<'..v..'></'..v..'>') -- e.g. '<entry.->.+</entry>' --> '<entry></entry>'
end
--DEFINE RSS MARKER TESTS
--Each of these test functions will be run in turn, until one of them gets a solid match on the format type.
local TestRSS = {
function(a)
-- If the feed contains these tags outside of <item> or <entry>, RSS is confirmed.
for _, v in ipairs{ '<rss', '<channel', '<lastBuildDate', '<pubDate', '<ttl', '<description' } do
if a:match(v) then
return 'RSS'
end
end
return false
end,
function(a)
-- Alternatively, if the feed contains these tags outside of <item> or <entry>, Atom is confirmed.
for _, v in ipairs{ '<feed', '<subtitle' } do
if a:match(v) then
return 'Atom'
end
end
return false
end,
function(a)
-- If no markers are present, we search for <item> or <entry> tags to confirm the type.
local HaveItems = a:match('<item')
local HaveEntries = a:match('<entry')
if HaveItems and not HaveEntries then
return 'RSS'
elseif HaveEntries and not HaveItems then
return 'Atom'
else
-- If both kinds of tags are present, and no markers are given, then I give up
-- because your feed is ridiculous. And if neither tag is present, then no type
-- can be confirmed (and there would be no usable data anyway).
return false
end
end
}
-- RUN RSS MARKER TESTS
local Class = false
for _, v in ipairs(TestRSS) do
Class = v(s)
if Class then break end
end
-- DETECT SUBTYPE AND RETURN
if Class == 'RSS' then
return 'RSS'
elseif Class == 'Atom' then
if s:match('xmlns:gCal') then
return 'GoogleCalendar'
elseif s:match('<subtitle>rememberthemilk.com</subtitle>') then
return 'RememberTheMilk'
else
return 'Atom'
end
else
return false
end
end
-------------------------
function IdentifyDate(s, t)
-- PARSE STRING BY TYPE
local Date
if s then
Date = Types[t].ParseDate(s) or Types.RSS.ParseDate(s) or Types.Atom.ParseDate(s) or {}
else
Date = {}
end
Date.year = tonumber(Date.year) or nil
Date.month = tonumber(Date.month) or MonthAcronyms[Date.month] or nil
Date.day = tonumber(Date.day) or nil
Date.hour = tonumber(Date.hour) or nil
Date.min = tonumber(Date.min) or nil
Date.sec = tonumber(Date.sec) or 0
-- FIND ENOUGH ELEMENTS, OR DEFAULT TO RETRIEVAL DATE
local RealDate, AllDay
if (Date.year and Date.month and Date.day) then
RealDate = 1
-- DETECT ALL-DAY EVENT
if (Date.hour and Date.min) then
AllDay = 0
else
AllDay = 1
Date.hour = 0
Date.min = 0
end
-- GET CURRENT LOCAL TIME, UTC OFFSET
-- These values are referenced in several procedures below.
local UTC = os.date('!*t')
local LocalTime = os.date('*t')
local DaylightSavings = LocalTime.isdst and 3600 or 0
local LocalOffset = os.time(LocalTime) - os.time(UTC) + DaylightSavings
-- CHANGE 12-HOUR to 24-HOUR
if Date.Meridiem then
if (Date.Meridiem == 'AM') and (Date.hour == 12) then
Date.hour = 0
elseif (Date.Meridiem == 'PM') and (Date.hour < 12) then
Date.hour = Date.hour + 12
end
end
-- FIND CLOSEST MATCH FOR TWO-DIGIT YEAR
if Date.year < 100 then
local CurrentYear = LocalTime.year
local CurrentCentury = math.floor(CurrentYear / 100) * 100
local IfThisCentury = CurrentCentury + Date.year
local IfNextCentury = CurrentCentury + Date.year + 100
if math.abs(CurrentYear - IfThisCentury) < math.abs(CurrentYear - IfNextCentury) then
Date.year = IfThisCentury
else
Date.year = IfNextCentury
end
end
-- GET INPUT OFFSET FROM UTC (OR DEFAULT TO LOCAL)
if (Date.Offset) and (Date.Offset ~= '') then
if Date.Offset:match('%a') then
Date.Offset = TimeZones[Date.Offset] and (TimeZones[Date.Offset] * 3600) or 0
elseif Date.Offset:match('%d') then
local Direction, Hours, Minutes = Date.Offset:match('^([^%d]-)(%d+)[^%d]-(%d%d)')
Direction = Direction:match('%-') and -1 or 1
Hours = tonumber(Hours) * 3600
Minutes = tonumber(Minutes) and (tonumber(Minutes) * 60) or 0
Date.Offset = (Hours + Minutes) * Direction
end
else
Date.Offset = LocalOffset
end
-- RETURN CONVERTED DATE
Date = os.time(Date) + LocalOffset - Date.Offset
else
-- NO USABLE DATE FOUND; USE RETRIEVAL DATE INSTEAD
RealDate = 0
AllDay = 0
Date = os.time()
end
return Date, AllDay, RealDate
end
-----------------------------------------------------------------------
-- EVENT FILE MODULE
function EventFile_Initialize()
local EventFiles = {}
local AllEventFiles = SELF:GetOption('EventFile', '')
for EventFile in AllEventFiles:gmatch('[^%|]+') do
table.insert(EventFiles, EventFile)
end
for i, v in ipairs(Feeds) do
local EventFile = EventFiles[i] or SELF:GetName()..'_Feed'..i..'Events.xml'
Feeds[i].EventFile = SKIN:MakePathAbsolute(EventFile)
end
end
function EventFile_Update(a)
local f = a or f
local WriteEvents = SELF:GetNumberOption('WriteEvents', 0)
if (WriteEvents == 1) and (Feeds[f].Type == 'GoogleCalendar') then
-- CREATE XML TABLE
local WriteLines = {}
table.insert(WriteLines, '<EventFile Title="'..Feeds[f].Title..'">')
for i, v in ipairs(Feeds[f]) do
local ItemDate = os.date('*t', v.Date)
table.insert(WriteLines, '<Event Month="'..ItemDate['month']..'" Day="'..ItemDate['day']..'" Desc="'..v.Title..'"/>')
end
table.insert(WriteLines, '</EventFile>')
-- WRITE FILE
local WriteFile = io.output(Feeds[f].EventFile, 'w')
if WriteFile then
local WriteContent = table.concat(WriteLines, '\r\n')
WriteFile:write(WriteContent)
WriteFile:close()
else
SKIN:Bang('!Log', SELF:GetName()..': cannot open file: '..Feeds[f].EventFile)
end
end
end
-----------------------------------------------------------------------
-- HISTORY FILE MODULE
function HistoryFile_Initialize()
-- DETERMINE FILEPATH
HistoryFile = SELF:GetOption('HistoryFile', SELF:GetName()..'History.xml')
HistoryFile = SKIN:MakePathAbsolute(HistoryFile)
-- CREATE HISTORY DATABASE
History = {}
-- CHECK IF FILE EXISTS
local ReadFile = io.open(HistoryFile)
if ReadFile then
local ReadContent = ReadFile:read('*all')
ReadFile:close()
-- PARSE HISTORY FROM LAST SESSION
for ReadFeedURL, ReadFeed in ReadContent:gmatch('<feed URL=(%b"")>(.-)</feed>') do
local ReadFeedURL = ReadFeedURL:match('^"(.-)"$')
History[ReadFeedURL] = {}
for ReadItem in ReadFeed:gmatch('<item>(.-)</item>') do
local Item = {}
for Key, Value in ReadItem:gmatch('<(.-)>(.-)</.->') do
Value = Value:gsub('<', '<')
Value = Value:gsub('>', '>')
Item[Key] = Value
end
Item.Date = tonumber(Item.Date) or Item.Date
Item.Unread = tonumber(Item.Unread)
table.insert(History[ReadFeedURL], Item)
end
end
end
-- ADD HISTORY TO MAIN DATABASE
-- For each feed, if URLs match, add all contents from History[h] to Feeds[f].
for f, Feed in ipairs(Feeds) do
local h = Feed.Measure:GetOption('URL')
Feeds[f].URL = h
if History[h] then
for _, Item in ipairs(History[h]) do
table.insert(Feeds[f], Item)
end
end
end
end
function HistoryFile_Update(a)
local f = a or f
-- CLEAR AND REBUILD HISTORY
local h = Feeds[f].URL
History[h] = {}
for i, Item in ipairs(Feeds[f]) do
table.insert(History[h], Item)
end
-- WRITE HISTORY IF REQUESTED
WriteHistory()
end
function WriteHistory()
local WriteHistory = SELF:GetNumberOption('WriteHistory', 0)
if WriteHistory == 1 then
-- GENERATE XML TABLE
local WriteLines = {}
for WriteURL, WriteFeed in pairs(History) do
table.insert(WriteLines, string.format( '<feed URL=%q>', WriteURL))
for _, WriteItem in ipairs(WriteFeed) do
table.insert(WriteLines, '\t<item>')
for Key, Value in pairs(WriteItem) do
Value = string.gsub(Value, '<', '<')
Value = string.gsub(Value, '>', '>')
table.insert(WriteLines, string.format( '\t\t<%s>%s</%s>', Key, Value, Key))
end
table.insert(WriteLines, '\t</item>')
end
table.insert(WriteLines, '</feed>')
end
-- WRITE XML TO FILE
local WriteFile = io.open(HistoryFile, 'w')
if WriteFile then
local WriteContent = table.concat(WriteLines, '\n')
WriteFile:write(WriteContent)
WriteFile:close()
else
SKIN:Bang('!Log', SELF:GetName()..': cannot open file: '..HistoryFile)
end
end
end
function ClearHistory()
local DeleteFile = io.open(HistoryFile)
if DeleteFile then
DeleteFile:close()
os.remove(HistoryFile)
SKIN:Bang('!Log', SELF:GetName()..': deleted history cache at '..HistoryFile)
end
SKIN:Bang('!Refresh')
end
-----------------------------------------------------------------------
-- CONSTANTS
TimeZones = {
IDLW = -12, -- International Date Line West
NT = -11, -- Nome
CAT = -10, -- Central Alaska
HST = -10, -- Hawaii Standard
HDT = -9, -- Hawaii Daylight
YST = -9, -- Yukon Standard
YDT = -8, -- Yukon Daylight
PST = -8, -- Pacific Standard
PDT = -7, -- Pacific Daylight
MST = -7, -- Mountain Standard
MDT = -6, -- Mountain Daylight
CST = -6, -- Central Standard
CDT = -5, -- Central Daylight
EST = -5, -- Eastern Standard
EDT = -4, -- Eastern Daylight
AST = -3, -- Atlantic Standard
ADT = -2, -- Atlantic Daylight
WAT = -1, -- West Africa
GMT = 0, -- Greenwich Mean
UTC = 0, -- Universal (Coordinated)
Z = 0, -- Zulu, alias for UTC
WET = 0, -- Western European
BST = 1, -- British Summer
CET = 1, -- Central European
MET = 1, -- Middle European
MEWT = 1, -- Middle European Winter
MEST = 2, -- Middle European Summer
CEST = 2, -- Central European Summer
MESZ = 2, -- Middle European Summer
FWT = 1, -- French Winter
FST = 2, -- French Summer
EET = 2, -- Eastern Europe, USSR Zone 1
EEST = 3, -- Eastern European Daylight
WAST = 7, -- West Australian Standard
WADT = 8, -- West Australian Daylight
CCT = 8, -- China Coast, USSR Zone 7
JST = 9, -- Japan Standard, USSR Zone 8
EAST = 10, -- Eastern Australian Standard
EADT = 11, -- Eastern Australian Daylight
GST = 10, -- Guam Standard, USSR Zone 9
NZT = 12, -- New Zealand
NZST = 12, -- New Zealand Standard
NZDT = 13, -- New Zealand Daylight
IDLE = 12 -- International Date Line East
}
MonthAcronyms = {
Jan = 1,
Feb = 2,
Mar = 3,
Apr = 4,
May = 5,
Jun = 6,
Jul = 7,
Aug = 8,
Sep = 9,
Oct = 10,
Nov = 11,
Dec = 12
}
-
- Posts: 1120
- Joined: January 22nd, 2011, 4:23 pm
- Location: GMT +8
Re: FeedReader w/ sorting
Fine but it just returns all Rainmeter Forums as a blank.. unless I've messed up somewhere with the paste/mergeKaelri wrote:I tested it on each of the feeds above, and it seems to handle all the dates.

( I pasted it over Reader.lua script of EverReader 0.4 to check and same result )
Last edited by Mordasius on October 2nd, 2012, 3:08 pm, edited 1 time in total.