Added a graph of general usage

This commit is contained in:
jyamihud 2022-04-16 13:37:13 +03:00
parent 079c922b73
commit 326347421b
6 changed files with 221 additions and 33 deletions

View file

@ -31,5 +31,33 @@
1650090012.933084, 1650090012.933084,
1650090481.4744847, 1650090481.4744847,
1650090521.486587, 1650090521.486587,
1650090584.648241 1650090584.648241,
1650095974.4940188,
1650097447.4327528,
1650100147.3385897,
1650100566.5777473,
1650102075.2005043,
1650103439.1721528,
1650103628.453873,
1650103669.108851,
1650103715.6338923,
1650103792.0688775,
1650103848.74207,
1650103929.5856616,
1650104068.4825075,
1650104211.148559,
1650104242.4403458,
1650104410.298269,
1650104561.913953,
1650104761.2695749,
1650104807.013614,
1650104867.3241987,
1650105102.2744603,
1650105197.1579733,
1650105202.8585582,
1650105210.2589703,
1650105235.6373727,
1650105264.9144416,
1650105289.841991,
1650105298.780408
] ]

View file

@ -137,6 +137,11 @@ p {
} }
.side_found { margin-top: 100} .side_found { margin-top: 100}
/*
If a screen is at least 1024 pixels wide, we do some more things.
*/
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
.recomendations { .recomendations {
margin-left: 40%;} margin-left: 40%;}
@ -151,4 +156,15 @@ p {
top:100; top:100;
left:5%;} } left:5%;} }
/* prgoress bar theme */
.back_progress {background-color: #543ba3;
width: 100%;
height: 7}
.back_progress:hover {
background-color: #CC35F0;
}
.front_progress {background-color: #96bbe8;
height: 7}
} }

View file

@ -1,17 +1,4 @@
<style> <!-- Frequently asked questions file is 'faq.html' . See Sources. -->
.test {
width: 30%;
height: 30%;
background: #928374;
position: fixed;
top: 5%;
right: 5%;
}
</style>
<div class="test">Some test text</div>
<h1>Frequently Asked Questions:</h1> <h1>Frequently Asked Questions:</h1>
@ -73,6 +60,30 @@
</p></span> </p></span>
</details> </details>
<details>
<summary>Does this website uses JavaScript?</summary>
<span><p>
No. We do not use a single line of JavaScript. Now, you are probably wondering how we make so many cool things with the website. Like progress bars and graphs? Well, we are using CSS for it. And CSS is really all you need to render pretty websites. JavaScript is really unnecessary. You can right-click and see sources of the pages. They have comments.
</p></span>
</details>
<details>
<summary>Does this website uses cookies or other trackers?</summary>
<span><p>
We do not use cookies. We respect the privacy of every person. Furthermore this website is designed to work over Tor. If you are connecting via .onion domain, we do not even see what Tor node is connecting. For the server, it seems like it's connecting to itself. So, if you using .onion site, we don't have anyway to even tell whether you connected to it before. Or how many times you connected to it. At a non .onion instance, your IP address will be visible to the website operator. The software is not configured to record them. But you have to trust the website operator. So we are advising to still use .onion version, or simply connect over Tor or VPN ( to anything ).</p>
<p>We do however see what is being searched. What pages are requested to be served and how often they are requested. For example, if you are requesting to see the Free Competitors for let's say <a href="/whatsapp">WhatsApp</a> it will request the server to render and send back the WhatsApp page. We can see when the server does it and what page is requested.</p>
<p>This fact lets us generate truly anonymous analytics. For example, we can detect what software is being searched, but not yet added into our database. So to create a list for us on what to work on.</p>
<p>One more thing that we can use it for. Is to get a <a href="/stats">general usage analytics</a>. Without counties and people's names. Just the amounts and times people used the site. For example, each time you load the web-site for the first time ( on each session of your browser ) it will request the favicon. A little logo to put in the corner of the tab. It does it only once per session ( usually ). So we can record the times when the favicon was requested to get a general idea of how many users use the site. Without knowing who they are, or anything about them.
</p></span>
</details>
<details> <details>
<summary>How does it find Competitors?</summary> <summary>How does it find Competitors?</summary>
<span><p> <span><p>
@ -134,3 +145,5 @@
<br><br> <br><br>
Now search for something and get a list of Free Competitors for it. Now search for something and get a list of Free Competitors for it.
<!-- After the document, the server software will attach the search and
footer. So there is no need to put it into the 'faq.html' document.-->

View file

@ -161,3 +161,51 @@ def List():
else: else:
s = s + " | |" s = s + " | |"
print(s) print(s)
def List_html():
# This function will list missing in html format
try:
with open("data/missing.json") as json_file:
missing = json.load(json_file)
# Reverse the old file
if type(missing) == dict:
missing = []
except:
missing = []
page = """
<h1>Known Missing Software</h1>
<p>This list is auto-generated by the server software when the software
cannot find a '.json' for for the searched query. It may or may not
be know to the developers, or even to the server operators. So please report
the software into <a href="https://notabug.org/jyamihud/FreeCompetitors/issues/25">
the Missing Software Page</a> in our source code repository.</p>
"""
for i in missing:
i = sorted(i.items(), key=lambda x:x[1])
i = dict(i)
if len(i) > 1:
page = page + "<details><summary>"+list(i.keys())[0]+"</summary>"
for b in i:
if b == list(i.keys())[0]:
continue
if b == list(i.keys())[-1]:
comma = ""
page = page + "<span>&nbsp;&nbsp;&nbsp;&nbsp;" + b + "</span><br>"
page = page + "</details>"
else:
page = page + list(i.keys())[0]+"<br>"
page = page + "\n\n"
return page

View file

@ -7,7 +7,9 @@
# your ability to set it up and running. # your ability to set it up and running.
import os import os
import time
from modules import search from modules import search
from modules import missing
def html(page, json): def html(page, json):
@ -319,6 +321,10 @@ def source_code_link(page):
<table><tr> <table><tr>
<th><form action=/>
<button title="Come back to the home page." type="submit">HOME</button>
</form></th>
<th><form action=https://notabug.org/jyamihud/FreeCompetitors> <th><form action=https://notabug.org/jyamihud/FreeCompetitors>
<button title="See the full source code of the software that powers this website." type="submit">SOURCE</button> <button title="See the full source code of the software that powers this website." type="submit">SOURCE</button>
</form></th> </form></th>
@ -337,6 +343,10 @@ def source_code_link(page):
<th><form action=https://notabug.org/jyamihud/FreeCompetitors/issues/24> <th><form action=https://notabug.org/jyamihud/FreeCompetitors/issues/24>
<button title="Report a mistake in data about software." type="submit">MISTAKE?</button> <button title="Report a mistake in data about software." type="submit">MISTAKE?</button>
</form></th>
<th><form action=/stats>
<button title="See stats of this server." type="submit">STATS</button>
</form></th></tr> </form></th></tr>
</table> </table>
@ -358,19 +368,11 @@ def progress(page, frac, text=""):
page = page + """ page = page + """
<!-- In order for this to work with any CSS file, the <!-- ============ PROGRESS BARS =============
style of the little progress bar should be defined Note that the progress bars will be visible only
inline. --> if the CSS file is configured for the divs of
the progress bars. Otherwise it will just show
<style> the text. -->
.back_progress {background-color: #543ba3;
width: 100%;
height: 7}
.front_progress {background-color: #96bbe8;
height: 7}
</style>
<!-- Then we are going to use two divs -->
<div class="back_progress"> <div class="back_progress">
<div class="front_progress" style="width:"""+str(frac*100)+"""%"> <div class="front_progress" style="width:"""+str(frac*100)+"""%">
@ -379,3 +381,62 @@ def progress(page, frac, text=""):
&nbsp;&nbsp;"""+str(text)+""" &nbsp;&nbsp;"""+str(text)+"""
""" """
return page return page
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 = []
print(days)
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'
frac = 100-(d/biggest*100)
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

View file

@ -93,13 +93,21 @@ class handler(BaseHTTPRequestHandler):
def send(self, textin): def send(self, textin):
software = self.path.replace("/", "").replace("+", " ")
if software:
software = ": "+software[0].upper()+software[1:].lower()
textin = str(textin) textin = str(textin)
csstext = '<link media="all" href="'+CSS+'" type="text/css" rel="stylesheet" />' csstext = '<link media="all" href="'+CSS+'" type="text/css" rel="stylesheet" />'
text = "<!-- Welcome to Free Competitors Page Source!!!--> \n\n" text = "<!-- Welcome to Free Competitors Page Source!!!--> \n\n"
text = text + "<!-- Let's add some CSS, you can edit 'config.json' to change it. -->\n" text = text + "<!-- Let's add some CSS, you can edit 'config.json' to change it. -->\n"
text = text + '<head>'+csstext+'\n\n' text = text + '<head>'+csstext+'\n\n'
text = text + "<!-- Now we want the favicon to be PNG instead of ICO -->\n\n" text = text + "<!-- Now we want the favicon to be PNG instead of ICO -->\n\n"
text = text + '<link rel="icon" href="favicon.png"></head>\n\n' text = text + '<link rel="icon" href="favicon.png">\n\n'
text = text + "<!-- Now the title -->\n\n"
text = text + '<title>Free Competitors'+software+'</title></head>\n\n'
text = text + "<!-- Now the body. The main part of the page, so to speak. -->\n" text = text + "<!-- Now the body. The main part of the page, so to speak. -->\n"
text = text + '<body>\n\n'+textin+'\n\n</body>' text = text + '<body>\n\n'+textin+'\n\n</body>'
@ -145,9 +153,9 @@ class handler(BaseHTTPRequestHandler):
# The css file # The css file
cssfile = open("default.css") cssfile = open("default.css", "rb")
cssfile = cssfile.read() cssfile = cssfile.read()
self.send(cssfile) self.wfile.write(cssfile)
elif self.path == "/font": elif self.path == "/font":
@ -155,7 +163,7 @@ class handler(BaseHTTPRequestHandler):
fontfile = open("OpenSans-ExtraBold.ttf", "rb") fontfile = open("OpenSans-ExtraBold.ttf", "rb")
fontfile = fontfile.read() fontfile = fontfile.read()
self.send(fontfile) self.wfile.write(fontfile)
elif self.path in ["/faq", "/faq?"]: elif self.path in ["/faq", "/faq?"]:
@ -195,6 +203,20 @@ class handler(BaseHTTPRequestHandler):
icon = icon.read() icon = icon.read()
self.wfile.write(icon) self.wfile.write(icon)
elif self.path in ["/stats", "/stats?"]:
# Analytics / statistics availble for all users of
# the website.
try:
with open("data/favicon_requests.json") as json_file:
favicons = json.load(json_file)
except:
favicons = []
page = render.stats("", True, favicons)
self.send(page)
elif "/search?item=" in self.path: elif "/search?item=" in self.path:
# Clearing the url # Clearing the url