Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

Feat: Searching feature on the main page; close #18 #19

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
60 changes: 48 additions & 12 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Code of Conduct

## v1 - Drafted by Izaac Saleh & Sukhwan Ko
## Versions

- v2 - Drafted by Sukhwan Ko
- <s>v1 - Drafted by Izaac Saleh & Sukhwan Ko</s>

## Our Pledge

Expand Down Expand Up @@ -55,22 +58,29 @@ any moderations they deem appropriate.

---

- Our online platform (website, forum, chatroom etc.)
- Code repository (including comments, pull requests, issue reports etc.)
- Project-related communication channels such as:
- Email
- Slack
- Microsoft Teams
- Discord
- Asana
- etc.
- In-person events(Conferences, meetups etc.)
**Our online platform**

- **Website**: The Code of Conduct applies to all comments, posts, and messages left on the website, including those in forums, discussion boards, or comment sections.
- **Forum**: The same rules apply to all discussions, threads, and topics within the forum, including those that are public or private.
- **Chatroom**: The Code of Conduct covers all conversations, messages, and files shared in chatroom, whether they're public or invited-only.

**Code repository**

- **Comments**: The Code applies to all comments left on code snippets, commits, or pull requests, as well as any replies or discussions that might arise.
- **Pull requests:** The same rules apply to all pull requests, including those for new features, bug fixes, or refactoring code.
- **Issue reports**: The Code of conduct covers all issue reports, whether they're related to bugs, feature requests, or documentation updates.

**Project-related communication channels**

- **Email**: The Code applies to all emails sent to the project's email list, including these that are public or private.
- **Microsoft Teams:** The Code of Conduct covers all discussions, meetings, and file shared within the project's Microsoft Teams space.
- **Discord(main):** The same rules apply to all voice or text chats, channels, and servers used by the project on Discord.

## Enforcement

---

Community leaders will take action to address violations of the Code of Conduct. The specific consequences will depend on the severity of the violation.
Our Community Leaders are responsible for clarifying and enforcing the standards of acceptable behaviour and are expected to lead by example. If a breach of the Code of Conduct is found to have occurred, Community Leaders are charged with taking appropriate but fair corrective action. Community Leaders have the responsibility, and maintain the right, to remove, edit, or reject comments, commits, code, issues, and other contributions that are not in alignment with this Code of Conduct. They will communicate the reasons for any moderation they deem appropriate.

## Enforcement Guidelines

Expand Down Expand Up @@ -100,6 +110,32 @@ Community leaders will take action to address violations of the Code of Conduct.

- **Consequence:** A permanent ban from any sort of public interaction within the community.

5. Additional Guidelines

- Initial Response: Upon receiving a report of potential Code of Conduct violation, our Community Leaders will acknowledge receipt and promptly investigate.
- Investigation Process:
- Gather information from all parties involved.
- Review relevant records and communications.
- Investigate in a fair and impartial manner.
- Communication During Investigation:
- Maintain open communication with all parties involved.
- Provide updates on the progress and outcome of the investigation.
- Decision-Making:
- Community Leaders will make decisions based on the findings and evidence gathered during the investigation.
- Consequences for Repeat Offenders:
- For repeat offenders, consequences may be escalated or combined (e.g., temporary ban and loss of privileges).
- Appeals Process:
- Establish a clear appeals process for individuals affected by enforcement decisions.
- Ensure that appeals are heard in a fair and impartial manner.

6. Resolving Disputes

- Dispute Resolution Committee: Establish a committee composed of community leaders to resolve disputes related to Code of Conduct violations.
- Dispute Resolution Process:
- Identify the nature of the dispute.
- Gather information from all parties involved.
- Make a fair and impartial decision.

## Attribution

This Code of Conduct is adapted from the GITHUB documents template for "code of conduct" found when adding a file of the
Expand Down
16 changes: 12 additions & 4 deletions app/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
import sys
import os.path
import logging
import shutil
Expand All @@ -9,6 +11,8 @@
import html
import glob

sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))

# Initialise flask app
app = Flask(__name__, static_url_path='/static', static_folder='static')
# Current video
Expand Down Expand Up @@ -230,9 +234,9 @@ def update_settings():
def reset_settings():
print("Current working directory:", os.getcwd())
# Delete the existing config.ini file
if os.path.exists('config.ini'):
os.remove('config.ini')
shutil.copy('config.example.ini', 'config.ini')
if os.path.exists('app/config.ini'):
os.remove('app/config.ini')
shutil.copy('app/config.example.ini', 'app/config.ini')
current_settings = utils.get_current_settings()
return render_template('settings.html', current_settings=current_settings)

Expand Down Expand Up @@ -275,9 +279,13 @@ def update_tesseract_path():
if __name__ == "__main__":
host = "localhost"
port = 5000
if utils.update_port():
port = 5002
else:
port = port
logging.basicConfig(filename="app.log", filemode="w", level=logging.DEBUG, format="%(levelname)s - %(message)s")
print("[*] Starting OcrRoo Server")
print(f"[*] OcrRoo Server running on http://{host}:{port}/")
app.run(host=host, port=port)
app.run(host=host, port=port, debug=True)
else:
logging.basicConfig(level=logging.DEBUG, format="%(levelname)s - %(message)s")
12 changes: 12 additions & 0 deletions app/static/js/filenameAdjust.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const targetNames = document.querySelectorAll('.uploaded-filenames');
const firstLength = 20;
const secondLength = 40;
const thirdLength = 60;

targetNames.forEach((item) => {
const first = item.textContent.slice(0, firstLength);
const second = item.textContent.slice(firstLength, secondLength);
const third = item.textContent.slice(secondLength, thirdLength);
const fourth = item.textContent.slice(thirdLength);
item.textContent = `${first}\n${second}\n${third}\n${fourth}`;
});
22 changes: 22 additions & 0 deletions app/static/js/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const inputElement = document.getElementById('search-in');
const searchResults = document.querySelectorAll(".continue-items");


inputElement.addEventListener('input', () => {
const query = inputElement.value.trim().toLowerCase();
searchResults.forEach((item) => {
// Do something with the item, e.g., log its text content
if (item.textContent.toLowerCase().includes(query)){
item.classList.remove('hidden');
}
else
{
item.classList.add('hidden');
}
if (query === "") {
item.classList.remove('hidden');
}
});

});

42 changes: 24 additions & 18 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,31 @@ <h2 class="text-lg {% if "username" in setup_progress %}line-through text-purple
bg-gradient-to-tr from-indigo-500 via-fuchsia-400 to-purple-400"><i class="fa-solid fa-house mr-4"></i>OcrRoo Home</h2>
{% endif %}
{% if continue_watching %}
<section class="mb-4">
<div>
<h2 class="text-2xl">Continue Watching</h2>
<section class="mb-4">
<div>
<h2 class="text-2xl mb-2">Continue Watching</h2>
<div class="search-bar border-2 bg-gray-150 p-4 w-full text-lg flex ">
<label class="m-4 pr-1 text-4xl" id="search-button">🔍</label>
<input class="search-bar-input w-full p-2 pl-10 pr-10 border border-gray-200 rounded-sm" type="search" id="search-in" placeholder="Search...">
</div>
<hr class="mb-4 mt-2">
<div class="flex overflow-x-auto gap-4">
<div class="flex flex-auto flex-wrap overflow-x-auto gap-4 justify-around">
{% for current_video in continue_watching %}
<div class="w-1/6 shrink-0 mb-2 border-gray-600 border bg-white">
<div class="continue-items w-1/4 shrink-0 mb-2 border-gray-600 border bg-white">
<a href="/play_video/{{ current_video["filename"] }}" >
<img class="border-gray-600 border border-b-0 w-full h-40"
src="{{url_for('static',filename='img/' + current_video["thumbnail"])}}"
alt="{{ current_video["alias"] }} Thumbnail">
</a>
<p style="width: {{ current_video["progress_percent"] }}%;" class="bg-gradient-to-tr from-indigo-500 via-fuchsia-400 to-purple-400 h-1 rounded-r-full">&nbsp</p>
<span class="flex justify-between items-center p-1">
<span>{{ current_video["alias"] }}</span>
<span class="whitespace-nowrap text-gray-500 text-sm">
{{ current_video["progress"] }} / {{ current_video["video_length"] }}
</span>
</span>
<div class="ml-1">
<p style="width: {{ current_video["progress_percent"] }}%;" class="font-bold bg-gradient-to-tr from-indigo-500 via-fuchsia-400 to-purple-400 h-1 rounded-r-full">&nbsp</p>
<p class="flex justify-between items-center p-1">
<p class="uploaded-filenames whitespace-wrap">{{ current_video["alias"] }}</p>
<p class=" text-gray-500 text-sm">
{{ current_video["progress"] }} / {{ current_video["video_length"] }}
</p>
</p>
</div>
<p class="text-gray-500 p-1 pt-0 text-sm">{{ current_video["captures"]|length }}
code capture/s
</p>
Expand All @@ -78,13 +84,13 @@ <h2 class="text-2xl">Your Video Library</h2>
src="{{url_for('static',filename='img/' + current_video["thumbnail"])}}"
alt="{{ current_video["alias"] }} Thumbnail">
</a>
<span class="flex w-full justify-between items-center p-1">
<span>{{ current_video["alias"] }}</span>
<span class="text-gray-500 text-sm">{{ current_video["video_length"] }}</span>
</span>
<p class="flex w-full justify-between items-center p-1">
<p>{{ current_video["alias"] }}</p>
<p class="text-gray-500 text-sm">{{ current_video["video_length"] }}</p>
</p>
<div class="flex w-full justify-between items-center px-1 pb-1">
<span class="text-gray-500 w-fit text-sm">{{ current_video["captures"]|length }} code capture/s
</span>
<p class="text-gray-500 w-fit text-sm">{{ current_video["captures"]|length }} code capture/s
</p>
<button onclick="deleteVideo('{{ current_video["filename"] }}')"
aria-label="delete video" class="text-red-400" type="button"><i class="fa-regular fa-trash-can"></i>
</button>
Expand Down
2 changes: 2 additions & 0 deletions app/templates/new-base.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@
</div>
</section>
<script src="{{url_for('static', filename='js/webCli.js')}}"></script>
<script src="{{url_for('static', filename='js/search.js')}}"></script>
<script src="{{url_for('static', filename='js/filenameAdjust.js')}}"></script>
</div>
</div>
</body>
Expand Down
49 changes: 31 additions & 18 deletions app/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sys
import os.path
import hashlib
import json
import os.path
import shutil
import subprocess
import logging
Expand All @@ -14,6 +15,8 @@
from pytube.exceptions import RegexMatchError
from configparser import ConfigParser

sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))


def config(section: str = None, option: str = None) -> Union[ConfigParser, str]:
"""
Expand All @@ -27,9 +30,9 @@ def config(section: str = None, option: str = None) -> Union[ConfigParser, str]:
if (section is None) != (option is None):
raise SyntaxError("section AND option parameters OR no parameters must be passed to function config()")
parser = ConfigParser()
if not os.path.exists("config.ini"):
shutil.copy("config.example.ini", "config.ini")
parser.read("config.ini")
if not os.path.exists("app/config.ini"):
shutil.copy("app/config.example.ini", "app/config.ini")
parser.read("app/config.ini")
if parser.get("AppSettings", "openai_api_key") != "your_openai_api_key_here":
openai.api_key = parser.get("AppSettings", "openai_api_key")
# TODO: This only needs to be set once, unsure if calling this will cause any performance issues same for
Expand Down Expand Up @@ -82,15 +85,15 @@ def read_user_data() -> json:
Reads the users data from json file
:return: Returns user data as json
"""
if not os.path.exists("data\\userdata.json"):
if not os.path.exists("data\\"):
os.makedirs("data\\")
with open("data\\userdata.json", "w") as user_data:
if not os.path.exists("app/data/userdata.json"):
if not os.path.exists("app/data/"):
os.makedirs("app/data/")
with open("app/data/userdata.json", "w") as user_data:
user_data.write(json.dumps({"all_videos": []}))
pass
return None
try:
with open("data\\userdata.json", "r") as user_data_json:
with open("app/data/userdata.json", "r") as user_data_json:
data = json.load(user_data_json)
return data
except JSONDecodeError:
Expand All @@ -106,7 +109,7 @@ def get_vid_save_path() -> str:
vid_download_path = config("UserSettings", "video_save_path")
# Set default output path for video download path
if vid_download_path == "output_path":
default_path = os.path.dirname(os.getcwd()) + "\\out\\videos\\"
default_path = os.path.dirname(os.getcwd()) + "/out/videos/"
if not os.path.exists(default_path):
os.makedirs(default_path)
return default_path
Expand All @@ -126,7 +129,7 @@ def get_output_path() -> str:
output_path = config("UserSettings", "capture_output_path")
# Set default output path for code files
if output_path == "output_path":
default_path = os.path.dirname(os.getcwd()) + "\\out\\"
default_path = os.path.dirname(os.getcwd()) + "/out/"
if not os.path.exists(default_path):
os.makedirs(default_path)
return default_path
Expand Down Expand Up @@ -266,7 +269,7 @@ def update_user_video_data(filename: str, progress: Optional[float] = None, capt
record["progress"] = round(progress)
if capture is not None:
record["captures"].append(capture)
with open("data/userdata.json", "w") as json_data:
with open("app/data/userdata.json", "w") as json_data:
json.dump(user_data, json_data, indent=4)


Expand Down Expand Up @@ -294,9 +297,9 @@ def add_video_to_user_data(filename: str, video_title: str, video_hash: str, you
return
thumbnail = str(int(time.time())) + ".png"
# Check if img dir exists if not create
if not os.path.exists("static/img"):
os.makedirs("static/img")
cv2.imwrite(f"static/img/{thumbnail}", frame)
if not os.path.exists("app/static/img"):
os.makedirs("app/static/img")
cv2.imwrite(f"app/static/img/{thumbnail}", frame)
new_video = {
"video_hash": video_hash,
"filename": filename,
Expand All @@ -310,7 +313,7 @@ def add_video_to_user_data(filename: str, video_title: str, video_hash: str, you
new_video["youtube_url"] = youtube_url
video_capture.release()
user_data["all_videos"].append(new_video)
with open("data/userdata.json", "w") as json_data:
with open("app/data/userdata.json", "w") as json_data:
json.dump(user_data, json_data, indent=4)


Expand Down Expand Up @@ -444,7 +447,7 @@ def delete_video_from_userdata(filename: str) -> None:
if current_video["filename"] == filename:
all_videos.remove(current_video)
break
with open("data/userdata.json", "w") as json_data:
with open("app/data/userdata.json", "w") as json_data:
json.dump(user_data, json_data, indent=4)


Expand All @@ -465,7 +468,7 @@ def update_configuration(new_values_dict) -> None:
value = str(value)
config_file.set(section, key, value)
# save the file
with open('config.ini', 'w') as config_file_save:
with open('app/config.ini', 'w') as config_file_save:
config_file.write(config_file_save)


Expand Down Expand Up @@ -530,3 +533,13 @@ def extract_form_values(request):
'use_youtube_downloader': youtube_downloader_enabled,
}
}


def update_port() -> bool:
"""
Checks if the current platform is a Unix-based system (like Darwin or Linux). If so, returns True.
:return: bool - True if running on a Unix-based system, False otherwise
"""
if sys.platform.lower() in ['darwin', 'linux']:
return True
return False
Loading
Loading