2022-03-29 14:44:03 +02:00
# THIS SOFTWARE IS A PART OF FREE COMPETITOR PROJECT
# THE FOLLOWING SOURCE CODE I UNDER THE GNU
# AGPL LICENSE V3 OR ANY LATER VERSION.
# This project is not for simple users, but for
# web-masters and a like, so we are counting on
# your ability to set it up and running.
2022-04-04 18:54:11 +02:00
import os
2022-04-16 12:37:13 +02:00
import time
2022-03-29 14:44:03 +02:00
from modules import search
2022-04-16 12:37:13 +02:00
from modules import missing
2022-04-02 00:10:18 +02:00
2022-04-11 21:18:21 +02:00
2022-03-29 14:44:03 +02:00
def html ( page , json ) :
# This function adds a rendering of the json into the page
2022-04-01 21:59:32 +02:00
free = search . is_free ( json )
2022-04-14 21:30:22 +02:00
name = json . get ( " names " , [ " Unknown " ] ) [ 0 ]
page = page + """
< ! - - For each software in the list we do mostly the same things .
And here it is . First we show it ' s name as a link to be able
to search Free Competitors to what is found . - - >
"""
page = page + " \n <a href= \" / " + name . replace ( " " , " + " ) . lower ( ) + " \" > "
page = page + " \n <h1> "
2022-03-29 14:44:03 +02:00
try :
2022-04-14 21:30:22 +02:00
page = page + ' \n <img src= " ' + json [ " links " ] [ " icon " ] + ' " alt= " [LOGO] " style= " height:50px; " > <!-- The logo of the software in question.--> \n '
2022-03-29 14:44:03 +02:00
except :
pass
2022-04-14 21:30:22 +02:00
page = page + " " + name + " <!-- The title of the program --> \n "
page = page + " </h1> \n </a> \n \n "
page = page + """
< ! - - Next there is a short paragraph about the program .
( Often Copypasted from some official page about it ) .
Which means , it may contain the terrible words " Open Source "
that hide the fact that Free Software is about User Freedom
first of all . So we are trying to link to a special page on
GNU . ORG if such a thing is found - - >
"""
2022-03-29 14:44:03 +02:00
# Few words about it
2022-04-02 13:11:49 +02:00
comment = json . get ( " comment " , " " )
2022-04-03 02:41:46 +02:00
not_foss = [ ' open source ' , ' open-source ' ]
if " open source " or " open-source " in comment . lower ( ) :
2022-04-02 13:11:49 +02:00
# Well... Here is a thing. Free Software, not open source.
where = comment . lower ( ) . find ( " open source " )
2022-04-03 02:41:46 +02:00
# In case it has a slash in it.
if where == - 1 :
where = comment . lower ( ) . find ( " open-source " )
2022-04-04 18:54:11 +02:00
ops = comment [ where : where + 11 ]
2022-04-14 21:30:22 +02:00
if ops :
comment = comment . replace ( ops ,
" <a href= \" https://www.gnu.org/philosophy/open-source-misses-the-point.en.html \" > " + ops + " </a> " )
page = page + " \n <p> \n " + comment + " \n </p> \n \n "
2022-03-29 14:44:03 +02:00
2022-03-31 20:08:42 +02:00
# I want to show nothing else from if it's proprietary
2022-04-04 18:54:11 +02:00
issues_files = list ( os . listdir ( " data/issues " ) )
2022-04-02 17:28:29 +02:00
if " issues " in json :
2022-03-31 20:08:42 +02:00
l = json . get ( " issues " , [ ] )
page = page + " <h2>Anti-Features / Problems:</h2> "
for i in l :
2022-04-04 18:54:11 +02:00
if i + " .html " not in issues_files :
page = page + " " + i + " <br> "
else :
page = page + ' <details title= " Read about ' + i + ' " > '
page = page + " <summary>   " + i + " </summary> "
issuefile = open ( " data/issues/ " + i + " .html " )
page = page + " <span><p> " + issuefile . read ( ) + " </p></span> "
page = page + " </details> "
2022-04-02 17:28:29 +02:00
if not free :
2022-03-31 20:08:42 +02:00
return page
2022-03-29 14:44:03 +02:00
# Links
2022-03-30 18:12:06 +02:00
2022-04-14 21:30:22 +02:00
page = page + """
2022-04-16 22:09:43 +02:00
2022-04-14 21:30:22 +02:00
< ! - - And now the table itself . - - >
2022-03-30 18:12:06 +02:00
"""
2022-04-05 20:21:04 +02:00
linksfilter = { " git " : " source " }
2022-03-31 20:08:42 +02:00
links = json . get ( " links " , { } )
for website in links :
if website in [ " icon " ] :
continue
link = links [ website ]
2022-03-31 19:16:16 +02:00
page = page + """
2022-04-14 21:30:22 +02:00
< ! - - Here ' s how to do a simple button -->
2022-04-16 22:09:43 +02:00
< a class = " button " href = \""" " +link+ """ \" title= \" " " " + link + """ \" > """ + linksfilter . get ( website , website ) . upper ( ) + """ </a>
2022-03-31 19:16:16 +02:00
"""
2022-04-14 21:30:22 +02:00
page = page + """
< ! - - Details are those little collapsable things that I like to
use very much . It ' s very simple really. Just read the code
carefully and you will get it - - >
"""
2022-03-30 18:12:06 +02:00
# Details
categories = { " generic_name " : " Features " ,
" licenses " : " License(s) " ,
" platforms " : " Platforms " ,
" networks_read " : " Accesses Data from " ,
" networks_write " : " Interacts / Publishes to " ,
" formats_read " : " Opens from File-Formats " ,
" formats_write " : " Saves to File-Formats " ,
2022-03-31 20:23:41 +02:00
" interface " : " Interface " ,
" languages " : " Programming Languages " }
2022-03-30 18:12:06 +02:00
for c in categories :
l = json . get ( c , [ ] )
if not l :
continue
2022-04-07 19:22:31 +02:00
# I want to look whether this category has a list of files
alldata = list ( os . listdir ( " data " ) )
allfiles = [ ]
for folder in alldata :
if c . startswith ( folder ) :
try :
allfiles = list ( os . listdir ( " data/ " + folder ) )
break
except :
pass
# Count matches
matches = 0
for i in l :
if i . startswith ( " * " ) :
matches + = 1
if matches :
matchtext = " <i>( " + str ( matches ) + " )</i> "
else :
matchtext = " "
2022-04-14 21:30:22 +02:00
page = page + " \n \n <details> "
page = page + " \n <summary> " + categories [ c ] + " : " + matchtext + " </summary> "
2022-03-30 18:12:06 +02:00
for i in l :
2022-04-07 19:22:31 +02:00
matchtext = " "
if i . startswith ( " * " ) :
i = i [ 1 : ]
matchtext = " <i>( match )</i> "
if i + " .html " in allfiles :
datapage = open ( " data/ " + folder + " / " + i + " .html " )
2022-04-14 21:30:22 +02:00
page = page + """
< ! - - Just so happened that about \""" " +i+ """ \" we had a file
in data / """ +folder+ """ folder . So why not make a detail inside a detail ,
a detail - sception , so to speak . And add the text of explanation into it . - - >
"""
page = page + " <details> \n "
page = page + " <summary> " + matchtext + i + " </summary> \n "
page = page + " <span> \n <p> \n "
page = page + " " + datapage . read ( ) + " \n "
page = page + " </p> \n </span> \n </details> "
2022-04-07 19:22:31 +02:00
else :
2022-04-14 21:30:22 +02:00
page = page + " \n <span> " + matchtext + i + " </span> \n <br> \n "
page = page + """
< ! - - Just a tiny space after all the spans . So no to feel
too crowded , so to speak - - >
< span > < br > < / span >
< / details >
"""
2022-03-30 18:12:06 +02:00
2022-03-29 14:44:03 +02:00
return page
def suggestions ( page , json ) :
# This function will render suggestions
2022-04-14 21:30:22 +02:00
page = page + """
< ! - - == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
This is where ther actual competitors are starting to show ! ! !
== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == - - >
< h1 > Free Competitors : < / h1 >
"""
2022-03-29 14:44:03 +02:00
found = search . suggest ( json )
2022-04-01 21:59:32 +02:00
biggest = 0
for i in found :
if i [ 0 ] > biggest :
biggest = i [ 0 ]
2022-04-02 17:28:29 +02:00
more = False
2022-03-29 14:44:03 +02:00
for i in found :
2022-04-01 21:59:32 +02:00
free = search . is_free ( i [ - 1 ] )
2022-03-30 19:52:36 +02:00
2022-04-08 18:11:38 +02:00
if not i [ 0 ] or i [ - 1 ] [ " names " ] == json [ " names " ] or not free :
2022-03-29 14:44:03 +02:00
continue
2022-04-02 17:28:29 +02:00
try :
frac = int ( i [ 0 ] / biggest * 100 )
except :
frac = 0
2022-04-07 19:22:31 +02:00
if frac < 20 and not more : # Below 40% features match
2022-04-14 21:30:22 +02:00
page = page + """
< ! - - Sometimes the suggestion is not very good . Below 40 %
of suggestion score . But it still kind of valid . So we
want to put it into the page . Only when the user clicks
something . Why not using the same old details ? - - >
< hr >
< details >
< summary > < h1 title = " Click to show more / less. " > Problematic Competitors : < / h1 > < / summary >
"""
2022-04-02 17:28:29 +02:00
more = True
2022-04-14 21:30:22 +02:00
page = page + """
2022-04-02 17:28:29 +02:00
2022-04-16 08:30:50 +02:00
< br > < br >
2022-04-14 21:30:22 +02:00
< ! - - == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == - - >
"""
2022-04-16 08:30:50 +02:00
page = progress ( page , frac / 100 , " Suggestion score: " + str ( frac ) + " % " )
2022-03-29 14:44:03 +02:00
page = html ( page , i [ - 1 ] )
2022-04-02 17:28:29 +02:00
if more :
page = page + " </details> "
2022-03-30 18:12:06 +02:00
return page
2022-04-03 18:27:21 +02:00
def search_widget ( page , address ) :
2022-03-30 18:12:06 +02:00
# Adds a search bar to the page
page = page + """
2022-04-14 21:30:22 +02:00
< ! - - Search widget ! This widget makes it possible to implement
a search feature without using a single line of JavaScript code .
In HTML , there is an input field that we can use . If we pare it
with a button into a < form > , we can get a button that activates
the search . - - >
2022-04-03 18:27:21 +02:00
< form action = """
page = page + address
page = page + """ search method= " GET " >
2022-03-30 18:12:06 +02:00
< input type = " text " name = " item " class = " search " placeholder = " Name of Software " >
< button type = " submit " > Search < / button >
< / form >
2022-04-14 21:30:22 +02:00
< ! - - And that ' s it for the search widget -->
2022-03-30 18:12:06 +02:00
"""
2022-04-03 18:27:21 +02:00
#page = page.format(ADDRESS)
2022-03-30 18:12:06 +02:00
return page
def source_code_link ( page ) :
# Adds a source code link
page = page + """
2022-04-14 21:30:22 +02:00
< ! - - This the the footer of every page - - >
2022-04-15 21:29:20 +02:00
< hr >
2022-04-15 21:25:42 +02:00
This website is under the GNU AGPL license .
2022-04-14 21:30:22 +02:00
< ! - - As always I want to add a bit of CSS to make tables
invisible - - >
2022-04-16 22:09:43 +02:00
< br > < br >
< a class = " button " href = " / " title = " Come back to the home page. " > HOME < / a >
< a class = " button " href = " https://notabug.org/jyamihud/FreeCompetitors " title = " See the full source code of the software that powers this website. " > SOURCE CODE < / a >
< a class = " button " href = " /faq " title = " Frequently Asked Questions " > FAQ < / a >
< a class = " button " href = " https://notabug.org/jyamihud/FreeCompetitors/issues " title = " Report a Bug. " > BUG ? < / a >
< a class = " button " href = " https://notabug.org/jyamihud/FreeCompetitors/issues/25 " title = " Report a piece of software that ' s missing from the catalogue. " > MISSING ? < / a >
< a class = " button " href = " https://notabug.org/jyamihud/FreeCompetitors/issues/24 " title = " Report a mistake in data about software. " > MISTAKE ? < / a >
< a class = " button " href = " https://notabug.org/jyamihud/FreeCompetitors/issues/24 " title = " See stats of this server. " > STATS < / a >
2022-04-14 21:30:22 +02:00
< ! - - And this was the page of Free Competitors . No Javascript .
No crap . No trackers . No nothing . And still works . Take that
Google ! ! ! - - >
2022-04-04 20:52:17 +02:00
2022-03-30 18:12:06 +02:00
"""
2022-04-16 08:30:50 +02:00
return page
def progress ( page , frac , text = " " ) :
# This will output a progress bar
page = page + """
2022-04-16 12:37:13 +02:00
< ! - - == == == == == == PROGRESS BARS == == == == == == =
Note that the progress bars will be visible only
if the CSS file is configured for the divs of
the progress bars . Otherwise it will just show
the text . - - >
2022-04-16 08:30:50 +02:00
< div class = " back_progress " >
< div class = " front_progress " style = " width: " " " + str ( frac * 100 ) + """ % " >
< / div >
< / div >
& nbsp ; & nbsp ; """ +str(text)+ """
"""
2022-03-29 14:44:03 +02:00
return page
2022-04-16 12:37:13 +02:00
def stats ( page , mis = False , data = [ ] ) :
# Graph will require some math to work.
# We are going to use CSS and HTML5 to
# draw it / interact with it.
spd = 60 * 60 * 24 # Seconds in each day
span = max ( data ) - min ( data ) # Time of seconds between first and last entry
days = span / spd # Time in days between first and last entry
# making sure there is at least something to show
if days < 20 :
data . append ( min ( data ) - ( spd * 20 ) )
spd = 60 * 60 * 24
span = max ( data ) - min ( data )
days = span / spd
widthfrac = 100 / days # the % to use for the width of each div
# Count how much hits happen per each day
biggest = 0
day_counts = [ ]
for d in range ( int ( round ( days ) ) ) :
count = 0
for i in data :
day = min ( data ) + ( d * spd )
if int ( i ) in range ( int ( day ) , int ( day + spd ) ) :
count + = 1
if count > biggest :
biggest = count
day_counts . append ( count )
# Render them
page = page + " <center> "
for n , d in enumerate ( day_counts ) :
if n == 0 :
d - = 1
dayis = min ( data ) + ( n * spd )
dayis = time . strftime ( " % Y/ % m/ %d " , time . gmtime ( dayis ) )
page = page + ' <div class= " front_progress " title= " ' + str ( dayis ) + ' : ' + str ( d ) + ' visitors " style= " height:400; position:absolute; top:5 % ; left:calc(99vw/ ' + str ( days ) + ' * ' + str ( n ) + ' ) ;width: ' + str ( widthfrac ) + ' % " > \n '
2022-04-16 13:19:08 +02:00
frac = 100 - ( d / biggest * 99 )
2022-04-16 12:37:13 +02:00
page = page + ' <div class= " back_progress " style= " height: ' + str ( frac ) + ' % ; bottom: ' + str ( frac ) + ' % " ></div></div> \n \n '
page = page + ' \n </center> \n \n <div style= " position:absolute; top:500 " > '
# If to render missing software
if mis :
page = page + missing . List_html ( )
page = source_code_link ( page )
return page