Skip to content

Commit 4241dee

Browse files
committed
merged upstream main and resolved conflicts
2 parents 30fbcbf + a781572 commit 4241dee

12 files changed

Lines changed: 477 additions & 180 deletions

File tree

.github/data/contributors-log.json

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
},
2020
"TIC_TAC_TOE": {
2121
"contributor-name": [
22-
"06RAVI06"
22+
"06RAVI06",
23+
"Tithi234"
2324
],
2425
"pull-request-number": [
25-
"7"
26+
"7",
27+
"77"
2628
],
2729
"demo-path": "TIC_TAC_TOE"
2830
},
@@ -150,10 +152,12 @@
150152
},
151153
"Pomodoro-Timer": {
152154
"contributor-name": [
153-
"adedayoprcs"
155+
"adedayoprcs",
156+
"Tithi234"
154157
],
155158
"pull-request-number": [
156-
"21"
159+
"21",
160+
"73"
157161
],
158162
"demo-path": "Pomodoro-Timer"
159163
},
@@ -285,10 +289,12 @@
285289
},
286290
"Auto-Clicker": {
287291
"contributor-name": [
288-
"BasselDar"
292+
"BasselDar",
293+
"Tithi234"
289294
],
290295
"pull-request-number": [
291-
"54"
296+
"54",
297+
"70"
292298
],
293299
"demo-path": "Auto-Clicker"
294300
},
@@ -309,5 +315,23 @@
309315
"62"
310316
],
311317
"demo-path": "Motion-Detection"
318+
},
319+
"Bowling-Action-Tracking": {
320+
"contributor-name": [
321+
"musharrafhamraz"
322+
],
323+
"pull-request-number": [
324+
"67"
325+
],
326+
"demo-path": "https://github.com/Grow-with-Open-Source/Python-Projects/tree/main/Bowling-Action-Tracking"
327+
},
328+
"Encryption_Project": {
329+
"contributor-name": [
330+
"moonabys"
331+
],
332+
"pull-request-number": [
333+
"75"
334+
],
335+
"demo-path": "Encryption_Project"
312336
}
313337
}

Auto-Clicker/auto_clicker.py

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,48 @@
22
import keyboard
33
import time
44

5-
clicking = False
65

6+
def run_auto_clicker(delay: float = 0.01) -> None:
7+
"""
8+
Runs an auto clicker that can be controlled with keyboard hotkeys.
79
8-
def start_clicking():
9-
global clicking
10-
clicking = True
11-
print("Auto clicker started")
10+
Controls:
11+
- Press 'S' to start clicking
12+
- Press 'E' to stop clicking
13+
- Press 'Q' to quit
14+
"""
15+
clicking = False
1216

17+
def start_clicking():
18+
nonlocal clicking
19+
clicking = True
20+
print("✅ Auto clicker started")
1321

14-
def stop_clicking():
15-
global clicking
16-
clicking = False
17-
print("Auto clicker stopped")
22+
def stop_clicking():
23+
nonlocal clicking
24+
clicking = False
25+
print("⏹ Auto clicker stopped")
26+
27+
keyboard.add_hotkey("s", start_clicking)
28+
keyboard.add_hotkey("e", stop_clicking)
29+
30+
print("Press 'S' to start clicking")
31+
print("Press 'E' to stop clicking")
32+
print("Press 'Q' to quit")
1833

34+
try:
35+
while True:
36+
if clicking:
37+
pyautogui.click()
38+
time.sleep(delay)
1939

20-
keyboard.add_hotkey("s", start_clicking)
21-
keyboard.add_hotkey("e", stop_clicking)
40+
if keyboard.is_pressed("q"):
41+
print("👋 Exiting program")
42+
break
2243

23-
print("Press 'S' to start clicking")
24-
print("Press 'E' to stop clicking")
25-
print("Press 'Q' to quit")
44+
except KeyboardInterrupt:
45+
print("\nProgram interrupted by user.")
2646

27-
while True:
28-
if clicking:
29-
pyautogui.click()
30-
time.sleep(0.001)
3147

32-
if keyboard.is_pressed("q"):
33-
print("Exiting program")
34-
break
48+
if __name__ == "__main__":
49+
run_auto_clicker()

Bowling-Action-Tracking/main.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import cv2
2+
import mediapipe as mp
3+
import numpy as np
4+
from collections import deque
5+
6+
# Initialize MediaPipe Pose
7+
mp_pose = mp.solutions.pose
8+
pose = mp_pose.Pose()
9+
mp_drawing = mp.solutions.drawing_utils
10+
11+
# Initialize video capture
12+
cap = cv2.VideoCapture('bowling.mp4')
13+
14+
# Store wrist trajectory and arcs
15+
wrist_trajectory = deque(maxlen=100) # Main wrist trajectory
16+
wrist_positions = deque(maxlen=20) # For arcs
17+
elbow_positions = deque(maxlen=20)
18+
shoulder_positions = deque(maxlen=20)
19+
20+
# Function to convert normalized coordinates to pixel coordinates
21+
def to_pixel_coords(landmark, frame):
22+
return int(landmark.x * frame.shape[1]), int(landmark.y * frame.shape[0])
23+
24+
# Function to draw a gradient arc between two points
25+
def draw_gradient_arc(frame, p1, p2, thickness, start_color, end_color):
26+
num_segments = 50
27+
x_diff = (p2[0] - p1[0]) / num_segments
28+
y_diff = (p2[1] - p1[1]) / num_segments
29+
30+
for i in range(num_segments):
31+
# Compute start and end points of each segment
32+
start_point = (int(p1[0] + i * x_diff), int(p1[1] + i * y_diff))
33+
end_point = (int(p1[0] + (i + 1) * x_diff), int(p1[1] + (i + 1) * y_diff))
34+
35+
# Interpolate color between start and end
36+
alpha = i / num_segments
37+
color = (
38+
int(start_color[0] * (1 - alpha) + end_color[0] * alpha),
39+
int(start_color[1] * (1 - alpha) + end_color[1] * alpha),
40+
int(start_color[2] * (1 - alpha) + end_color[2] * alpha),
41+
)
42+
cv2.line(frame, start_point, end_point, color, thickness)
43+
44+
while cap.isOpened():
45+
ret, frame = cap.read()
46+
if not ret:
47+
break
48+
frame = cv2.resize(frame, (1000, 600))
49+
# Convert the frame to RGB
50+
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
51+
results = pose.process(rgb_frame)
52+
53+
if results.pose_landmarks:
54+
landmarks = results.pose_landmarks.landmark
55+
56+
# Extract right-hand keypoints
57+
right_shoulder = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER]
58+
right_elbow = landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW]
59+
right_wrist = landmarks[mp_pose.PoseLandmark.RIGHT_WRIST]
60+
61+
# Convert normalized coordinates to pixel coordinates
62+
shoulder_coords = to_pixel_coords(right_shoulder, frame)
63+
elbow_coords = to_pixel_coords(right_elbow, frame)
64+
wrist_coords = to_pixel_coords(right_wrist, frame)
65+
66+
# Add wrist coordinates to the deque for trajectory
67+
wrist_trajectory.append(wrist_coords)
68+
69+
# Add coordinates for arcs
70+
shoulder_positions.append(shoulder_coords)
71+
elbow_positions.append(elbow_coords)
72+
wrist_positions.append(wrist_coords)
73+
74+
# Draw the wrist trajectory (main line)
75+
for i in range(1, len(wrist_trajectory)):
76+
cv2.line(frame, wrist_trajectory[i - 1], wrist_trajectory[i], (0, 255, 255), 3)
77+
78+
# Draw dynamic arcs for the last few positions
79+
for i in range(1, len(shoulder_positions)):
80+
# Fade effect using index
81+
thickness = max(2, 10 - (len(shoulder_positions) - i))
82+
83+
# Gradient arc for shoulder-to-elbow
84+
draw_gradient_arc(frame, shoulder_positions[i - 1], elbow_positions[i - 1], thickness, (0, 255, 0), (255, 0, 0))
85+
# Gradient arc for elbow-to-wrist
86+
draw_gradient_arc(frame, elbow_positions[i - 1], wrist_positions[i - 1], thickness, (255, 0, 0), (0, 0, 255))
87+
88+
# Draw keypoints
89+
cv2.circle(frame, shoulder_coords, 10, (0, 255, 0), -1) # Shoulder
90+
cv2.circle(frame, elbow_coords, 10, (255, 0, 0), -1) # Elbow
91+
cv2.circle(frame, wrist_coords, 10, (0, 0, 255), -1) # Wrist
92+
93+
# Display the frame
94+
cv2.imshow('Dynamic Bowling Trajectory', frame)
95+
96+
if cv2.waitKey(10) & 0xFF == ord('q'):
97+
break
98+
99+
cap.release()
100+
cv2.destroyAllWindows()
101+
102+
103+

Encryption_Project/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Encryption Project
2+
3+
For now this project can only encrypt messages using the following methods:
4+
5+
* SHA-256
6+
* AES-128
7+
* Base64
8+
9+
*If you want to understand how this works, this project comments all around it to make sure you understand what's happening*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Let's start with AES
2+
# AES is a type of encryption used mainly for things that require certain level of safety and later will be used
3+
# There is a specific thing you shouldn't encrypt with AES that's Passkeys
4+
# For passkeys you will use a method showed later that are the Hash Methods
5+
6+
# In this example we using pycryptodome
7+
8+
from Crypto.Cipher import AES
9+
10+
def encrypt_aes(message: str, key: str):
11+
encrypt_cipher = AES.new(key, AES.MODE_EAX) # This is the "configuration" for the encryption
12+
13+
nonce = encrypt_cipher.nonce # Nonce aka Number Once is basically what makes the key random
14+
15+
encrypted_message = encrypt_cipher.encrypt_and_digest(message) # Here we are truly encrypting the message
16+
17+
return encrypted_message, nonce
18+
19+
def decrypt_aes(message: bytes, key: bytes, nonce: bytes):
20+
decrypt_cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) # Here we are Saying what's the key, type of encryption and nonce
21+
decrypted_message = decrypt_cipher.decrypt(message)
22+
return decrypted_message
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Let's start
2+
# Base64 is NOT a safe way to encrypt important things, it's used to encrypt binary data to text and doesn't have a key such as AES
3+
# If you pretend encrypting something that you need to know later you should use AES
4+
# Else you just want to encrypt something and doesn't care about the privacy Base64 might be a good choice
5+
6+
# In this example we are using a pre-installed module from Python called "base64"
7+
8+
import base64
9+
10+
def encrypt_base64(message: str):
11+
encrypt_message = base64.b64encode(message.encode()).decode()
12+
return encrypt_message
13+
14+
def decrypt_base64(message: str):
15+
decrypt_message = base64.b64decode(message).decode('utf-8')
16+
return decrypt_message
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Let's start with Hashes! (more specifically SHA256)
2+
# Hashes are a way to encrypt thing in a irreversible way
3+
# This means if you encrypt something using Hash Methods there is no way to know the content
4+
5+
# In this example we using pre-installed module called "hashlib"
6+
7+
import hashlib
8+
9+
def encryption_sha(message: str):
10+
return hashlib.sha256().digest() # This makes the encryption in SHA-256. This is the usually how your passkeys are encrypted

Encryption_Project/main.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from encryption import sha, aes, base64
2+
import os
3+
4+
def main():
5+
while True:
6+
print("""Welcome to Encryption Project\n
7+
1 - SHA256\n
8+
2 - AES\n
9+
3 - Base64\n
10+
4 - Quit\n
11+
More soon!\n""")
12+
13+
encrypt_choice = int(input())
14+
15+
match encrypt_choice:
16+
case 1:
17+
message_to_encrypt = input("What's the message you want to encrypt?: ")
18+
19+
encrypted_message = sha.encryption_sha(message_to_encrypt)
20+
21+
print(f"The encrypted message is: {encrypted_message}")
22+
23+
case 2:
24+
aes_choice = int(input("1 - Encrypt\n2 - Decrypt\n"))
25+
26+
if aes_choice == 1:
27+
message_to_encrypt = input("What's the message you want to encrypt? ").encode('utf-8')
28+
key = os.urandom(16) # if you are confused, this just guarantee the key will have 16 bytes
29+
30+
encrypted_message, nonce = aes.encrypt_aes(message_to_encrypt, key)
31+
32+
print(f"Encrypted message: {encrypted_message}\nnonce: {nonce}\nkey: {key}\n *Save those!*")
33+
elif aes_choice == 2:
34+
message_to_decrypt = eval(input("What's the message to decrypt? "))
35+
key = eval(input("What's the key? "))
36+
nonce = eval(input("What's the nonce? "))
37+
38+
decrypted_message = aes.decrypt_aes(message_to_decrypt, key, nonce)
39+
40+
print(f"Message: {decrypted_message}")
41+
42+
else:
43+
print("Option does not exist")
44+
45+
case 3:
46+
base_choice = int(input("1 - Encrypt\n2 - Decrypt\n"))
47+
48+
if base_choice == 1:
49+
message_to_encrypt = input("What's the message you want to encrypt? ")
50+
51+
encrypted_message = base64.encrypt_base64(message_to_encrypt)
52+
53+
print(f"Message: {encrypted_message}")
54+
55+
elif base_choice == 2:
56+
message_to_decrypt = input("What's the message to decrypt? ")
57+
58+
decrypted_message = base64.decrypt_base64(message_to_decrypt)
59+
60+
print(f"Message: {decrypted_message}")
61+
62+
else:
63+
print("Option does not exist")
64+
65+
case 4:
66+
print("Bye!")
67+
break
68+
69+
case _:
70+
print("This option is not available")
71+
72+
if __name__ == "__main__":
73+
main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pycryptodome

0 commit comments

Comments
 (0)