Skip to content

Commit e33cff9

Browse files
committed
rss: sheets: parse spreadsheet rows
1 parent 5cd737c commit e33cff9

File tree

4 files changed

+262
-3
lines changed

4 files changed

+262
-3
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
.env
66
.local_cache/*
77
*.log
8+
**/.secrets/*
89
internet/*.txt

pyproject.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
requires-python = ">=3.13"
99
version = "0.1.0"
1010
dependencies = [
11+
"gspread>=6.1.4",
1112
"mypy>=1.13.0",
13+
"oauth2client>=4.1.3",
1214
"playwright>=1.48.0",
1315
"pydantic>=2.9.2",
1416
"requests>=2.32.3",
1517
"rich>=13.9.3",
1618
"ruff>=0.7.1",
1719
"sendgrid>=6.11.0",
1820
"typer>=0.12.5",
19-
]
21+
]
2022

2123
[dependency-groups]
2224
dev = ["types-requests>=2.32.0.20241016"]

rss/subscriptions/add/sheets.py

+104-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,108 @@
1-
"""Handler for bulk subscribing to URLs saved to a Google Sheet."""
1+
"""
2+
Handler for bulk subscribing to URLs saved to a Google Sheet.
3+
4+
SETUP:
5+
6+
Step 1: Set Up Google Cloud Project
7+
- Go to the Google Cloud Console: https://console.cloud.google.com/
8+
- Create a new project.
9+
- Enable the Google Sheets API for the project: https://console.cloud.google.com/apis/dashboard
10+
- See: https://docs.gspread.org/en/latest/oauth2.html
11+
12+
Step 2: Create Service Account
13+
- In the Google Cloud Console, go to IAM & Admin > Service Accounts.
14+
- Create a new service account.
15+
- Download the JSON key file for the service account.
16+
17+
Step 3: Share Google Sheet
18+
- Open the Google Sheet you want to interact with.
19+
- Share the sheet with the service account email (found in the JSON key file).
20+
"""
21+
22+
from enum import Enum
23+
from pathlib import Path
24+
from typing import Literal
25+
26+
from gspread.auth import authorize
27+
from gspread.client import Client
28+
from gspread.worksheet import Worksheet
29+
from oauth2client.service_account import ServiceAccountCredentials
30+
from pydantic import BaseModel
31+
32+
from common.logs import log
33+
34+
GOOGLE_CLOUD_CREDENTIALS_JSON = Path.cwd() / "rss/subscriptions/add/.secrets/google-cloud-service-account.json"
35+
GOOGLE_CLOUD_SCOPES = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
36+
SHEET_NAME = "RSS Feed Wish List 🔖"
37+
STATUS_COLUMN_INDEX = 3
38+
URL_COLUMN_NAME = "URL to subscribe to"
39+
40+
41+
class Status(Enum):
42+
SUBSCRIBED = "Subscribed"
43+
ERROR = "Error"
44+
45+
46+
class Row(BaseModel):
47+
index: int
48+
url: str
49+
status: Status | Literal[""]
50+
51+
52+
# Authenticate and create a client
53+
def get_authenticated_sheets_client(
54+
credentials_json: Path = GOOGLE_CLOUD_CREDENTIALS_JSON,
55+
scopes: list[str] = GOOGLE_CLOUD_SCOPES,
56+
) -> Client:
57+
# TODO: get keyfile from 1Password?
58+
creds = ServiceAccountCredentials.from_json_keyfile_name(credentials_json, scopes)
59+
client = authorize(creds)
60+
return client
61+
62+
63+
def get_worksheet(client: Client, sheet_name: str = SHEET_NAME) -> Worksheet:
64+
return client.open(sheet_name).sheet1
65+
66+
67+
def get_rows(sheet: Worksheet) -> list[Row]:
68+
data = sheet.get_all_records()
69+
70+
return [
71+
Row(
72+
index=i,
73+
url=str(row[URL_COLUMN_NAME]),
74+
status=Status(row["Status"]) if row["Status"] else "",
75+
)
76+
for i, row in enumerate(data, start=1)
77+
]
78+
79+
80+
# TODO: return what happened
81+
def update_row_status(
82+
*,
83+
sheet: Worksheet,
84+
row: int,
85+
col: int = STATUS_COLUMN_INDEX,
86+
status: Status,
87+
) -> None:
88+
sheet.update_cell(row, col, status.value)
89+
90+
91+
def main() -> None:
92+
client = get_authenticated_sheets_client()
93+
sheet = get_worksheet(client)
94+
rows = get_rows(sheet)
95+
log.debug(f"🔍 rows: {rows}")
96+
97+
# TODO: Subscribe to URLs
98+
99+
# Update status for the first URL
100+
# update_row_status(sheet=sheet, row=2, status=Status.SUBSCRIBED)
101+
102+
103+
if __name__ == "__main__":
104+
main()
2105

3-
# TODO: get authenticated sheets client
4106
# TODO: get URLs from sheet
5107
# TODO: subscribe to URLs
6108
# TODO: update status in sheet

uv.lock

+154
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)