-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphoto_frame_sync.py
More file actions
140 lines (118 loc) · 4.39 KB
/
Copy pathphoto_frame_sync.py
File metadata and controls
140 lines (118 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""Syncs photos from a local folder to a Pix-Star digital photo frame via email.
Keeps track of sent photos using a local SQLite database to avoid duplicates.
"""
import os
import json
import smtplib
import sqlite3
from pathlib import Path
from email.message import EmailMessage
from mimetypes import guess_type
# Location of secrets/config file (SMTP credentials, Pix-Star email)
# i.e.
# {
# "SMTP_SERVER": "*****",
# "SMTP_PORT": **,
# "SMTP_USERNAME": "****",
# If using gmail, this should be an app password
# "SMTP_PASSWORD": "****",
# "PIXSTAR_EMAIL": "****"
# }
CONFIG_PATH = Path("photo_frame_sync_config/secrets.json")
# Folder containing the photos to be synced to the photo frame
PHOTO_DIR = Path(r"E:/Photos/Digital Photo Frame")
# SQLite database to track which photos have already been sent
DB_PATH = Path("photo_frame_sync_data/sent_photos.db")
# Load email credentials and target address from the secrets file
with open(CONFIG_PATH, encoding="utf-8") as f:
config = json.load(f)
SMTP_SERVER = config["SMTP_SERVER"]
SMTP_PORT = config.get("SMTP_PORT", 465)
SMTP_USERNAME = config["SMTP_USERNAME"]
SMTP_PASSWORD = config["SMTP_PASSWORD"]
PIXSTAR_EMAIL = config["PIXSTAR_EMAIL"]
def init_db():
"""
Initializes the SQLite database and ensures the sent_photos table exists.
Returns:
sqlite3.Connection: A connection object to the SQLite database.
"""
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(DB_PATH)
with conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS sent_photos (
filename TEXT PRIMARY KEY
)
""")
return conn
def has_been_sent(conn, filename):
"""
Checks if a given filename has already been recorded as sent.
Args:
conn (sqlite3.Connection): SQLite database connection.
filename (str): The filename to check.
Returns:
bool: True if the filename is already recorded as sent, False otherwise.
"""
cur = conn.execute("SELECT 1 FROM sent_photos WHERE filename = ?", (filename,))
return cur.fetchone() is not None
def mark_as_sent(conn, filename):
"""
Records a filename as sent to the database.
Args:
conn (sqlite3.Connection): SQLite database connection.
filename (str): The filename to record.
"""
with conn:
conn.execute("INSERT OR IGNORE INTO sent_photos (filename) VALUES (?)", (filename,))
# --- Email Sender ---
def send_photo_via_email(file_path: Path):
"""
Sends a single photo as an email attachment to the Pix-Star digital photo frame.
Args:
file_path (Path): Path to the image file to be sent.
Raises:
smtplib.SMTPException: If email sending fails.
OSError: If reading the file fails.
"""
msg = EmailMessage()
msg['Subject'] = 'New Photo'
msg['From'] = SMTP_USERNAME
msg['To'] = PIXSTAR_EMAIL
msg.set_content("See attached photo.")
# Guess MIME type for proper email attachment formatting
mime_type, _ = guess_type(file_path.name)
maintype, subtype = mime_type.split("/") if mime_type else ("application", "octet-stream")
# Attach the photo
with open(file_path, 'rb') as f:
msg.add_attachment(f.read(), maintype=maintype, subtype=subtype, filename=file_path.name)
# Send the email using SSL
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
server.login(SMTP_USERNAME, SMTP_PASSWORD)
server.send_message(msg)
print(f"Sent: {file_path.name}")
# --- Main Orchestration ---
def sync_photos():
"""
Scans the photo directory for new images and sends them via email if they haven't been sent yet.
Records each successfully sent image in the local SQLite database.
"""
conn = init_db()
# Get list of supported image file types
photos = sorted(PHOTO_DIR.glob("*.jpg")) + \
sorted(PHOTO_DIR.glob("*.jpeg")) + \
sorted(PHOTO_DIR.glob("*.png")) + \
sorted(PHOTO_DIR.glob("*.gif")) + \
sorted(PHOTO_DIR.glob("*.heic"))
# Loop through photos and send those not yet emailed
for photo in photos:
if not has_been_sent(conn, photo.name):
try:
send_photo_via_email(photo)
mark_as_sent(conn, photo.name)
except Exception as e:
print(f"Failed to send {photo.name}: {e}")
conn.close()
if __name__ == "__main__":
sync_photos()