2022-04-03 20:04:47 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
2022-03-29 14:43:19 +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.
|
|
|
|
|
|
|
|
# Server side
|
|
|
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
|
|
from subprocess import *
|
|
|
|
import json
|
|
|
|
import os
|
2022-04-15 19:40:53 +02:00
|
|
|
import time
|
2022-03-29 14:43:19 +02:00
|
|
|
|
|
|
|
from modules import search
|
|
|
|
from modules import render
|
|
|
|
|
2022-04-03 20:04:47 +02:00
|
|
|
# Author: https://www.delftstack.com/howto/python/python-print-colored-text/
|
|
|
|
class bcolors:
|
|
|
|
OK = '\033[92m' #GREEN
|
|
|
|
WARNING = '\033[93m' #YELLOW
|
|
|
|
FAIL = '\033[91m' #RED
|
|
|
|
RESET = '\033[0m' #RESET COLOR
|
|
|
|
|
|
|
|
print("""╔═╗┬─┐┌─┐┌─┐╔═╗┌─┐┌┬┐┌─┐┌─┐┌┬┐┬┌┬┐┌─┐┬─┐┌─┐
|
|
|
|
╠╣ ├┬┘├┤ ├┤ ║ │ ││││├─┘├┤ │ │ │ │ │├┬┘└─┐
|
|
|
|
╚ ┴└─└─┘└─┘╚═╝└─┘┴ ┴┴ └─┘ ┴ ┴ ┴ └─┘┴└─└─┘
|
|
|
|
|
2022-04-03 21:15:20 +02:00
|
|
|
Copyright (C) 2022 Jeison Yehuda Amihud and contributors.
|
2022-03-31 19:16:16 +02:00
|
|
|
|
2022-04-03 20:04:47 +02:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2022-04-03 19:35:04 +02:00
|
|
|
|
2022-04-03 20:04:47 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
""")
|
|
|
|
|
|
|
|
print("Loading config...")
|
|
|
|
if os.path.exists("config.json"):
|
2022-04-03 19:35:04 +02:00
|
|
|
with open("config.json","r") as f:
|
|
|
|
srvConfig = json.load(f)
|
|
|
|
ADDRESS = srvConfig["address"]
|
|
|
|
PORT = srvConfig["port"]
|
|
|
|
CSS = srvConfig["css"]
|
2022-04-03 20:04:47 +02:00
|
|
|
print(bcolors.OK + "Loaded Configuration: " + bcolors.RESET)
|
|
|
|
print("Address: "+ ADDRESS)
|
|
|
|
print("Port: "+ str(PORT)) # Do not think people are smart at syntax
|
|
|
|
print("CSS: "+ CSS)
|
|
|
|
try:
|
|
|
|
PORT = int(PORT)
|
|
|
|
except:
|
|
|
|
print(bcolors.FAIL + "ERR: Port should be a number" + bcolors.RESET)
|
|
|
|
exit()
|
|
|
|
else:
|
2022-04-03 18:27:21 +02:00
|
|
|
newConfig = open("config.json", "w")
|
|
|
|
newConfig.write("""{
|
|
|
|
"INFO" : "You would be better off setting address to the full URL of the FreeCompetitors instance.",
|
|
|
|
"address" : "/",
|
2022-04-03 19:35:04 +02:00
|
|
|
"port" : 8080,
|
2022-04-04 18:34:28 +02:00
|
|
|
"css" : "/css"
|
2022-04-03 18:27:21 +02:00
|
|
|
}""")
|
|
|
|
newConfig.close
|
2022-04-03 20:04:47 +02:00
|
|
|
print(bcolors.WARNING + "Please edit the configuration file \"config.json\"." + bcolors.RESET)
|
2022-04-03 18:27:21 +02:00
|
|
|
exit()
|
2022-04-03 19:35:04 +02:00
|
|
|
|
2022-03-29 14:43:19 +02:00
|
|
|
# Who fucking made this http.server so I need to use classes?
|
|
|
|
# I fucking hate who ever thought that it was a good idea...
|
|
|
|
class handler(BaseHTTPRequestHandler):
|
|
|
|
|
|
|
|
def start_page(self):
|
|
|
|
self.send_response(200)
|
2022-04-04 18:34:28 +02:00
|
|
|
if "/json/" in self.path:
|
2022-04-02 09:43:52 +02:00
|
|
|
self.send_header('Content-type', 'application/json')
|
2022-04-04 18:34:28 +02:00
|
|
|
elif self.path == "/css":
|
|
|
|
self.send_header('Content-type', 'text/css')
|
|
|
|
elif self.path == "/ttf":
|
|
|
|
self.send_header('Content-type', 'font/ttf')
|
2022-04-15 19:40:53 +02:00
|
|
|
elif self.path in ["/favicon.png", "/logo"]:
|
|
|
|
self.send_header('Content-type', 'image/png')
|
2022-04-04 18:34:28 +02:00
|
|
|
else:
|
|
|
|
self.send_header('Content-type', 'text/html')
|
2022-03-29 14:43:19 +02:00
|
|
|
self.end_headers()
|
|
|
|
|
2022-04-14 21:30:22 +02:00
|
|
|
def send(self, textin):
|
2022-04-15 19:40:53 +02:00
|
|
|
|
2022-04-14 21:30:22 +02:00
|
|
|
textin = str(textin)
|
2022-03-29 14:43:19 +02:00
|
|
|
csstext = '<link media="all" href="'+CSS+'" type="text/css" rel="stylesheet" />'
|
2022-04-14 21:30:22 +02:00
|
|
|
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"
|
2022-04-15 21:25:42 +02:00
|
|
|
text = text + '<head>'+csstext+'\n\n'
|
2022-04-15 19:40:53 +02:00
|
|
|
text = text + "<!-- Now we want the favicon to be PNG instead of ICO -->\n\n"
|
2022-04-15 21:25:42 +02:00
|
|
|
text = text + '<link rel="icon" href="favicon.png"></head>\n\n'
|
2022-04-14 21:30:22 +02:00
|
|
|
text = text + "<!-- Now the body. The main part of the page, so to speak. -->\n"
|
|
|
|
text = text + '<body>\n\n'+textin+'\n\n</body>'
|
2022-03-29 14:43:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.start_page()
|
|
|
|
self.wfile.write(text.encode("utf-8"))
|
|
|
|
|
|
|
|
def do_GET(self):
|
2022-03-30 19:52:14 +02:00
|
|
|
|
2022-04-02 09:43:52 +02:00
|
|
|
if self.path.startswith("/json/"):
|
2022-03-29 14:43:19 +02:00
|
|
|
|
2022-04-02 09:43:52 +02:00
|
|
|
# API CALL
|
|
|
|
|
|
|
|
|
|
|
|
term = self.path[6:]
|
|
|
|
software_data, match = search.search_app(term)
|
|
|
|
data = {"found":{"data":software_data,"match":match}}
|
|
|
|
data["suggestions"] = search.suggest(software_data)
|
|
|
|
text = json.dumps(data, indent = 2)
|
|
|
|
|
|
|
|
self.start_page()
|
|
|
|
self.wfile.write(text.encode("utf-8"))
|
2022-04-15 19:40:53 +02:00
|
|
|
|
|
|
|
|
2022-04-02 09:43:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
elif self.path == "/":
|
2022-03-29 14:43:19 +02:00
|
|
|
|
|
|
|
# If the user is at the front page, let him get only the search bar
|
2022-03-30 18:11:55 +02:00
|
|
|
|
2022-04-15 19:40:53 +02:00
|
|
|
page = """<center>
|
|
|
|
<br><br><br>
|
|
|
|
|
|
|
|
<img src="/logo" alt="[LOGO]" style="height:150px;">
|
|
|
|
<h1>Free Competitors</h1>"""
|
2022-04-03 18:27:21 +02:00
|
|
|
page = render.search_widget(page, ADDRESS)
|
2022-04-01 21:59:32 +02:00
|
|
|
page = page + "<p>Please search for any software to which you would like to find a Free Software replacement.</p></center>"
|
2022-03-30 18:11:55 +02:00
|
|
|
page = render.source_code_link(page)
|
|
|
|
self.send(page)
|
2022-03-29 14:43:19 +02:00
|
|
|
|
2022-04-04 18:34:28 +02:00
|
|
|
elif self.path == "/css":
|
|
|
|
|
|
|
|
# The css file
|
|
|
|
|
|
|
|
cssfile = open("default.css")
|
|
|
|
cssfile = cssfile.read()
|
|
|
|
self.send(cssfile)
|
|
|
|
|
|
|
|
elif self.path == "/font":
|
|
|
|
|
|
|
|
# The font file
|
|
|
|
|
|
|
|
fontfile = open("OpenSans-ExtraBold.ttf", "rb")
|
|
|
|
fontfile = fontfile.read()
|
|
|
|
self.send(fontfile)
|
2022-04-06 21:03:07 +02:00
|
|
|
|
|
|
|
elif self.path in ["/faq", "/faq?"]:
|
|
|
|
|
|
|
|
# The font file
|
|
|
|
|
|
|
|
faqfile = open("faq.html")
|
|
|
|
faqfile = faqfile.read()
|
|
|
|
faqfile = render.search_widget(faqfile, ADDRESS)
|
|
|
|
faqfile = render.source_code_link(faqfile)
|
|
|
|
self.send(faqfile)
|
2022-04-04 18:34:28 +02:00
|
|
|
|
2022-04-15 19:40:53 +02:00
|
|
|
elif "/favicon.png" == self.path:
|
|
|
|
|
|
|
|
# I'm recording all the favicons request times to get
|
|
|
|
# a rough estimate of how many people visit when.
|
|
|
|
# It seems like the browser is visiting the site for
|
|
|
|
# the first time ( at least in a given session ) it
|
|
|
|
# asks for a 'favicon.ico'. So I store each of those
|
|
|
|
# requests time. As a timestamp.
|
2022-04-04 18:34:28 +02:00
|
|
|
|
2022-04-15 19:40:53 +02:00
|
|
|
try:
|
|
|
|
with open("data/favicon_requests.json") as json_file:
|
|
|
|
favicons = json.load(json_file)
|
|
|
|
except:
|
|
|
|
favicons = []
|
|
|
|
favicons.append(time.time())
|
|
|
|
with open("data/favicon_requests.json", 'w') as f:
|
|
|
|
json.dump(favicons, f, indent=4, sort_keys=True)
|
|
|
|
|
|
|
|
icon = open("favicon.png", "rb")
|
|
|
|
icon = icon.read()
|
|
|
|
self.wfile.write(icon)
|
|
|
|
|
|
|
|
elif "/logo" == self.path:
|
|
|
|
|
|
|
|
icon = open("favicon.png", "rb")
|
|
|
|
icon = icon.read()
|
|
|
|
self.wfile.write(icon)
|
2022-04-04 18:34:28 +02:00
|
|
|
|
2022-03-29 14:43:19 +02:00
|
|
|
elif "/search?item=" in self.path:
|
|
|
|
|
|
|
|
# Clearing the url
|
|
|
|
# instead of it being /search?item=softwarename
|
|
|
|
# it will be just /softwarename
|
|
|
|
|
|
|
|
item = self.path[self.path.find("item=")+5:].lower()
|
|
|
|
self.send('<meta http-equiv="Refresh" content="0; url=\'/'+item+'\'" />')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# This is when the fun is
|
|
|
|
|
|
|
|
software = self.path.replace("/", "").replace("+", " ")
|
|
|
|
|
2022-04-01 21:29:15 +02:00
|
|
|
software_data, match = search.search_app(software)
|
2022-04-15 21:25:42 +02:00
|
|
|
|
|
|
|
page = ""
|
|
|
|
page = page + '<div class="searchbar">'
|
|
|
|
page = page + render.search_widget("", ADDRESS)
|
|
|
|
page = page + "</div>"
|
|
|
|
|
|
|
|
page = page + '<div class="side_found">'
|
2022-04-01 21:59:32 +02:00
|
|
|
page = page +"Search match: "+ str(int(match*100))+"%"
|
2022-03-29 14:43:19 +02:00
|
|
|
# Let's add the found software to the page
|
|
|
|
page = render.html(page, software_data)
|
2022-04-15 21:25:42 +02:00
|
|
|
page = page + "</div>"
|
|
|
|
|
|
|
|
page = page + '<div class="recomendations">'
|
2022-03-29 14:43:19 +02:00
|
|
|
page = render.suggestions(page, software_data)
|
2022-03-30 18:11:55 +02:00
|
|
|
page = render.source_code_link(page)
|
2022-04-15 21:25:42 +02:00
|
|
|
page = page + "</div>"
|
|
|
|
|
2022-03-29 14:43:19 +02:00
|
|
|
|
|
|
|
self.send(page)
|
|
|
|
|
|
|
|
serve = HTTPServer(("", PORT), handler)
|
2022-04-03 20:04:47 +02:00
|
|
|
print(bcolors.OK + "⚡Now serving on port "+ str(PORT) +" at "+ ADDRESS +"." + bcolors.RESET)
|
2022-03-29 14:43:19 +02:00
|
|
|
serve.serve_forever()
|