App update

This commit is contained in:
Caretaker0699 2023-06-30 13:59:48 -07:00
parent 69cd65fbf0
commit f6ebf7b4fa
9 changed files with 419 additions and 228 deletions

Binary file not shown.

15
app.py
View File

@ -2,6 +2,7 @@ from flask import Flask, render_template, request, jsonify
import xml.etree.ElementTree as ET
import logging
app = Flask(__name__)
# Configure logging
@ -104,19 +105,5 @@ def report():
return jsonify(response)
# Schedule the xmldownloader.py to run every hour
def run_xmldownloader():
subprocess.run(['python', 'xmldownloader.py'])
if __name__ == '__main__':
# Schedule the xmldownloader.py to run every hour
schedule.every().hour.do(run_xmldownloader)
# Run the Flask app
app.run()
# Start the scheduled job in a separate thread
while True:
schedule.run_pending()
time.sleep(1)

1
cron.txt Normal file
View File

@ -0,0 +1 @@
0 * * * * python /home/heartily/Heartily/xmldownloader.py >> /home/heartily/Heartily/logfile.log 2>&1

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
<?xml version='1.0' encoding='utf-8'?>
<root></root>
<root><item title="Digital Communications Director - Positive Alternative Radio, Inc. - Gray, TN" link="https://www.indeed.com/viewjob?t=Digital+Communications+Director&amp;c=Positive+Alternative+Radio&amp;l=Gray,+TN&amp;jk=3958d8ee293ca079&amp;rtk=1h46i3kjai0ct800&amp;from=rss" /></root>

View File

@ -1,165 +1,253 @@
body {
background-color: #272822;
background-color: #272822;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #272822;
max-width: 800px;
margin: 0 auto;
padding: 30px;
background-color: #272822;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
color: #f8f8f2;
font-size: 32px;
font-weight: bold;
margin-bottom: 10px;
color: #f8f8f2;
}
ul {
list-style: none;
padding: 0;
list-style: none;
padding: 0;
}
li {
margin-bottom: 20px;
margin-bottom: 20px;
}
h2 {
font-size: 20px;
font-weight: bold;
color: #a9dc76;
font-size: 24px;
font-weight: bold;
color: #f8f8f2;
}
p {
color: #999999;
color: #999999;
}
a {
color: #78dce8;
text-decoration: none;
color: #78dce8;
text-decoration: none;
}
a:hover {
color: #e6a96b;
color: #e6a96b;
}
header {
display: flex;
justify-content: center;
align-items: center;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
flex-direction: row;
display: flex;
align-items: center;
}
.logo-img {
width: 50px;
max-width: 100%;
margin-right: 10px;
width: 40px;
max-width: 100%;
margin-right: 10px;
}
.logo p {
font-size: 24px;
color: #f8f8f2;
margin: 10px;
font-size: 32px;
color: #f8f8f2;
margin: 10px;
}
.logo-name {
font-size: 24px;
font-weight: bold;
color: #f8f8f2;
margin: 10px;
font-size: 32px;
font-weight: bold;
color: #f8f8f2;
margin: 10px;
}
.logo-link {
display: inline-flex;
align-items: center;
text-decoration: none; /* Add this line to remove underline */
display: inline-flex;
align-items: center;
text-decoration: none;
}
.search-form {
display: flex;
align-items: center;
justify-content: center;
display: flex;
align-items: center;
justify-content: center;
}
.search-input {
padding: 10px;
border: none;
border-radius: 4px;
font-size: 16px;
background-color: #F9F5DD;
color: #75715e;
padding: 10px;
border: none;
border-radius: 5px;
font-size: 16px;
background-color: #f9f5dd;
color: #75715e;
width: 200px;
margin: 10px;
}
.search-input::placeholder {
color: #75715e;
color: #75715e;
}
.search-button {
padding: 10px 20px;
border: none;
border-radius: 4px;
font-size: 16px;
background-color: #fd971f;
color: #f8f8f2;
cursor: pointer;
margin:10px;
padding: 10px 20px;
border: none;
border-radius: 5px;
font-size: 16px;
background-color: #fd971f;
color: #f8f8f2;
cursor: pointer;
margin: 10px;
}
.search-button:hover {
background-color: #f4bf75;
background-color: #f4bf75;
}
.notification-overlay {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #ff5795c7;
color: #f8f8f2;
border: 1px solid #272822;
padding: 10px 20px;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
animation: fadeIn 0.5s, fadeOut 0.5s 5s forwards;
display: none;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.report-button {
position: relative;
display: flex;
text-decoration: none;
padding: 10px 20px;
border-radius: 4px;
color: #FF5794;
border:none;
background-color: transparent;
margin: 5px;
.notification-overlay {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #ff5795c7;
color: #f8f8f2;
border: 5px solid #272822;
padding: 20px;
border-radius: 5px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
animation: fadeIn 0.5s, fadeOut 0.5s 5s forwards;
display: none;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.report-button {
position: relative;
display: flex;
text-decoration: none;
padding: 10px 20px;
border-radius: 5px;
color: #999999;
border: none;
background-color: transparent;
margin: 10px;
}
.wrapper {
position: relative;
display: inline-block;
text-decoration: none;
color: #f8f8f2;
background-color: #fd971f;
padding: 10px 20px;
border: none;
border-radius: 5px;
margin: 5px;
}
.wrapper .button-text {
display: inline-block;
transition: opacity 0.3s ease;
font-size: 16px;
}
.wrapper .button-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #f8f8f2;
font-size: 20px;
opacity: 0;
transition: opacity 0.3s ease;
}
.wrapper:hover {
background-color: #f4bf75;
}
.wrapper:hover .button-text {
opacity: 0;
}
.wrapper:hover .button-icon {
opacity: 1;
font-size: 13px;
}
.report-button .button-text {
display: inline-block;
transition: opacity 0.3s ease;
opacity: 0;
}
.report-button .button-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
transition: opacity 0.3s ease;
font-size: 25px;
opacity: 1;
}
.report-button:hover .button-text {
opacity: 1;
}
.report-button:hover .button-icon {
opacity: 0;
}
.list-container {
display: flex;
align-items: center;
}
.listed-items {
border: 1px solid #a0d170;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
transition: border 0.3s ease, background-color 0.3s ease;
}
.listed-items:hover {
border: 1px solid #d1d1d1;
background-color: #f0f0f007;
}
/* CSS code for the load more button */
.load-more-button {
position: relative;
display: inline-block;
text-decoration: none;
@ -167,63 +255,117 @@ header {
background-color: #fd971f;
padding: 10px 20px;
border: none;
border-radius: 4px;
border-radius: 5px;
margin: 5px;
}
}
.wrapper .button-text {
.load-more-button .button-text {
display: inline-block;
transition: opacity 0.3s ease;
}
font-size: 16px;
}
.wrapper .button-icon {
.load-more-button .button-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #ffffff;
font-size: 24px;
color: #f8f8f2;
font-size: 20px;
opacity: 0;
transition: opacity 0.3s ease;
}
.wrapper:hover {
}
.load-more-button:hover {
background-color: #f4bf75;
}
.wrapper:hover .button-text {
opacity: 0;
}
}
.wrapper:hover .button-icon {
.load-more-button:hover .button-text {
opacity: 0;
}
.load-more-button:hover .button-icon {
opacity: 1;
font-size: 20px;
}
.report-button .button-text {
display: inline-block;
transition: opacity 0.3s ease;
opacity: 0;
}
font-size: 13px;
}
.report-button .button-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* CSS code for the scroll button */
.scroll-to-top-button {
position: fixed;
bottom: 20px;
right: 20px;
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background-color: #fd971f;
color: #f8f8f2;
font-size: 20px;
text-align: center;
line-height: 40px;
cursor: pointer;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 9999;
}
.scroll-to-top-button.show {
opacity: 1;
}
/* Mobile Breakpoints */
/* Extra small devices (phones, 600px and down) */
@media only screen and (max-width: 600px) {
.search-input {
width: 100%;
}
.search-button {
margin-left: 0;
}
.wrapper,
.report-button {
font-size: 14px;
padding: 10px 15px;
}
.logo p,
.logo-name {
font-size: 24px;
transition: opacity 0.3s ease;
margin: 10px 5px;
}
}
/* Small devices (portrait tablets and large phones, 600px and up) */
@media only screen and (min-width: 600px) {
.wrapper,
.report-button {
font-size: 18px;
padding: 10px 15px;
}
}
/* Medium devices (landscape tablets, 768px and up) */
@media only screen and (min-width: 768px) {
.wrapper,
.report-button {
font-size: 20px;
opacity: 1;
}
}
.report-button:hover .button-text {
opacity: 1;
/* Large devices (laptops/desktops, 992px and up) */
@media only screen and (min-width: 992px) {
.wrapper,
.report-button {
font-size: 16px;
}
}
.report-button:hover .button-icon {
opacity: 0;
/* Extra large devices (large laptops and desktops, 1200px and up) */
@media only screen and (min-width: 1200px) {
.wrapper,
.report-button {
font-size: 14px;
}
}
.list-container {
display: flex;
align-items: center;
}

View File

@ -42,13 +42,14 @@
</form>
<h1>Latest Jobs:</h1>
<p>This list is updated hourly. Last update: {{ run_time }}</p>
<ul>
<ul id="item-list">
{% for item in items %}
<li>
<li class="listed-items" {% if loop.index>
5 %}style="display: none;"{% endif %}>
<h2>{{ item.title }}</h2>
<p>Source: {{ item.source }}</p>
<p>Post Date: {{ item.pub_date }}</p>
<div class = "list-container">
<div class="list-container">
<a href="{{ item.link }}" target="_blank" class="wrapper">
<span class="button-text">Apply Now</span>
<span class="button-icon"><i class="far fa-heart"></i></span>
@ -71,14 +72,19 @@
</li>
{% endfor %}
</ul>
<button id="load-more-button" class="load-more-button" {% if items|length|int <= 5 %}style="display: none;"{% endif %}>Load More</button>
</div>
<button id="scroll-to-top-button" class="scroll-to-top-button">
<i class="fas fa-arrow-up"></i>
</button>
<footer>
<p>
&copy; 2023 Heartily. All rights reserved. Version:
&copy; 2023 Heartily. All rights reserved. Version:
<a href="https://githaven.org/Shiloh/heartily" target="_blank">Beta</a>.
Powered by
<a href="https://shilohcode.com" target="_blank">Shiloh</a>.
Powered by <a href="https://shilohcode.com" target="_blank">Shiloh</a>.
</p>
</footer>
@ -88,38 +94,97 @@
</div>
<script>
// JavaScript code for displaying the notification overlay
function showNotification(message) {
var overlay = document.getElementById("notification-overlay");
var notification = document.getElementById("notification-message");
notification.textContent = message;
overlay.style.display = "block";
setTimeout(function () {
overlay.style.display = "none";
}, 10000); // Display the notification for 10 seconds
// JavaScript code for displaying the notification overlay
function showNotification(message) {
var overlay = document.getElementById("notification-overlay");
var notification = document.getElementById("notification-message");
notification.textContent = message;
overlay.style.display = "block";
setTimeout(function () {
overlay.style.display = "none";
}, 10000); // Display the notification for 10 seconds
}
// JavaScript code for handling the AJAX request and displaying the notification
var reportForms = document.getElementsByClassName("report-form");
Array.prototype.forEach.call(reportForms, function (form) {
form.addEventListener("submit", function (event) {
event.preventDefault(); // Prevent the form from submitting
// Create a new FormData object to send the form data
var formData = new FormData(form);
// Send the AJAX request
var xhr = new XMLHttpRequest();
xhr.open("POST", "/report");
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
showNotification(response.message); // Display the notification
}
};
xhr.send(formData);
});
});
// JavaScript code for handling load more button.
var itemList = document.getElementById("item-list");
var loadMoreButton = document.getElementById("load-more-button");
var itemsToShow = 5;
var totalItems = {{ items|length|tojson }};
function toggleLoadMoreButton() {
if (itemsToShow >= totalItems) {
loadMoreButton.style.display = "none";
} else {
loadMoreButton.style.display = "block";
}
}
function showAdditionalItems() {
var items = itemList.children;
for (var i = 0; i < totalItems; i++) {
if (i >= itemsToShow) {
items[i].style.display = "none";
} else {
items[i].style.display = "block";
}
}
}
function loadMoreItems() {
itemsToShow += 5;
showAdditionalItems();
toggleLoadMoreButton();
}
loadMoreButton.addEventListener("click", loadMoreItems);
// Show the initial set of items
showAdditionalItems();
toggleLoadMoreButton();
//javascript for handling the scroll to top button
var scrollToTopButton = document.getElementById("scroll-to-top-button");
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: "smooth"
});
}
// JavaScript code for handling the AJAX request and displaying the notification
var reportForms = document.getElementsByClassName("report-form");
Array.prototype.forEach.call(reportForms, function (form) {
form.addEventListener("submit", function (event) {
event.preventDefault(); // Prevent the form from submitting
function toggleScrollToTopButton() {
if (window.pageYOffset > 100) {
scrollToTopButton.classList.add("show");
} else {
scrollToTopButton.classList.remove("show");
}
}
// Create a new FormData object to send the form data
var formData = new FormData(form);
// Send the AJAX request
var xhr = new XMLHttpRequest();
xhr.open("POST", "/report");
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
showNotification(response.message); // Display the notification
}
};
xhr.send(formData);
});
});
scrollToTopButton.addEventListener("click", scrollToTop);
window.addEventListener("scroll", toggleScrollToTopButton);
</script>
</body>
</html>

View File

@ -1,5 +1,4 @@
import xml.etree.ElementTree as ET
import urllib.request
import random
import time
from fake_useragent import UserAgent
@ -12,11 +11,11 @@ current_datetime = datetime.datetime.now()
# Format the date and time as a string
run_time = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
# Print the run time
print("Script run time:", run_time)
# Define the URL of the XML file to download
url = "https://rss.indeed.com/rss?q=(it+OR+technology+OR+developer+OR+software)+AND+(bible+OR+christian+OR+jesus+OR+god)+-LDS+-%22Latter-Day+Saints%22.xml"
# Define the list of URLs
urls = [
"https://rss.indeed.com/rss?q=(it+OR+technology+OR+developer+OR+software)+AND+(bible+OR+christian+OR+jesus)+-LDS+-%22Latter-Day+Saints%22+-catholic+-christian.&fromage=14",
"https://rss.indeed.com/rss?q=(marketing+OR+UI+OR+design)+AND+(bible+OR+christian+OR+jesus)+-LDS+-%22Latter-Day+Saints%22+-catholic+-christian.&fromage=14",
]
# Set a custom user agent
ua = UserAgent()
@ -33,41 +32,38 @@ headers = {
session = requests.Session()
session.headers.update(headers)
# Download the XML file
response = session.get(url)
filename = "/home/gordon/Documents/Code/heartily/indeed_input.xml"
with open(filename, 'wb') as f:
f.write(response.content)
# Create a new XML root element to store all the extracted values
output_root = ET.Element("root")
# Introduce a random delay between 2 and 5 seconds
delay = random.uniform(2, 5)
time.sleep(delay)
for url in urls:
# Download the XML file
response = session.get(url)
content = response.content
# Read the downloaded XML file
tree = ET.parse(filename)
root = tree.getroot()
# Read the downloaded XML content
tree = ET.fromstring(content)
# Define the desired attribute names
attribute_names = ["title", "link", "source", "guid", "pubDate", "description", "{http://www.georss.org/georss}point"]
# Define the desired attribute names
attribute_names = ["title", "link", "source", "guid", "pubDate", "description", "{http://www.georss.org/georss}point"]
# Create a new XML root element to store the extracted values
new_root = ET.Element("root")
# Iterate over the "item" elements and extract the desired values
for item in tree.findall(".//item"):
new_element = ET.SubElement(output_root, "item")
# Iterate over the "item" elements and extract the desired values
for item in root.findall(".//item"):
new_element = ET.SubElement(new_root, "item")
# Extract the desired attributes from the "item" element
for attribute_name in attribute_names:
value = item.find(attribute_name).text
if value is not None:
new_element.set(attribute_name, value)
# Extract the desired attributes from the "item" element
for attribute_name in attribute_names:
value = item.find(attribute_name).text
if value is not None:
new_element.set(attribute_name, value)
# Add a new element for the run time
run_time_element = ET.SubElement(new_root, "run_time")
run_time_element = ET.SubElement(output_root, "run_time")
run_time_element.text = run_time
# Create an ElementTree object and write it to a new XML file
new_tree = ET.ElementTree(new_root)
output_filename = "/home/gordon/Documents/Code/heartily/indeed_output.xml"
new_tree.write(output_filename, encoding="utf-8", xml_declaration=True)
# Create an ElementTree object with the output root
output_tree = ET.ElementTree(output_root)
# Write the output to the XML file, overwriting the existing data
output_filename = "./indeed_output.xml"
with open(output_filename, 'wb') as f:
output_tree.write(f, encoding="utf-8", xml_declaration=True)