{"id":17058722,"url":"https://github.com/smkent/safeway-coupons","last_synced_at":"2025-04-05T07:01:39.635Z","repository":{"id":5551557,"uuid":"6755817","full_name":"smkent/safeway-coupons","owner":"smkent","description":"🥫 🎫 Automatic coupon clipper for Safeway's online \"Safeway for U\" coupons","archived":false,"fork":false,"pushed_at":"2025-01-15T20:23:35.000Z","size":505,"stargazers_count":62,"open_issues_count":10,"forks_count":19,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-03-29T06:01:37.369Z","etag":null,"topics":["container","coupons","cronjob","docker","python","safeway"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smkent.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2012-11-19T06:17:58.000Z","updated_at":"2025-01-15T20:00:36.000Z","dependencies_parsed_at":"2023-02-16T00:15:47.603Z","dependency_job_id":"4dfee2f4-5b77-4217-80d7-85848e7023fa","html_url":"https://github.com/smkent/safeway-coupons","commit_stats":{"total_commits":120,"total_committers":4,"mean_commits":30.0,"dds":"0.033333333333333326","last_synced_commit":"b8c81490473c0c2ea711f60e3f2138363c4d5b3e"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smkent%2Fsafeway-coupons","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smkent%2Fsafeway-coupons/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smkent%2Fsafeway-coupons/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smkent%2Fsafeway-coupons/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smkent","download_url":"https://codeload.github.com/smkent/safeway-coupons/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299828,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container","coupons","cronjob","docker","python","safeway"],"created_at":"2024-10-14T10:30:36.590Z","updated_at":"2025-04-05T07:01:39.584Z","avatar_url":"https://github.com/smkent.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Automatic Safeway coupon clipper\n\n[![PyPI](https://img.shields.io/pypi/v/safeway-coupons)][pypi]\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/safeway-coupons)][pypi]\n[![Build](https://img.shields.io/github/checks-status/smkent/safeway-coupons/main?label=build)][gh-actions]\n[![codecov](https://codecov.io/gh/smkent/safeway-coupons/branch/main/graph/badge.svg)][codecov]\n[![GitHub stars](https://img.shields.io/github/stars/smkent/safeway-coupons?style=social)][repo]\n\n**safeway-coupons** is a script that will log in to an account on safeway.com,\nand attempt to select all of the \"Safeway for U\" electronic coupons on the site\nso they don't have to each be clicked manually.\n\n## Design notes\n\nSafeway's sign in page is protected by a web application firewall (WAF).\nsafeway-coupons performs authentication using a headless instance of Google\nChrome. Authentication may fail based on your IP's reputation, either by\npresenting a CAPTCHA or denying sign in attempts altogether. safeway-coupons\ncurrently does not have support for prompting the user to solve CAPTCHAs.\n\nOnce a signed in session is established, coupon clipping is performed using HTTP\nrequests via [requests][requests].\n\n## Installation and usage with Docker\n\nA Docker container is provided which runs safeway-coupons with cron. The cron\nschedule and your Safeway account details may be configured using environment\nvariables, or with an accounts file.\n\nExample `docker-compose.yaml` with configuration via environment variables:\n\n```yaml\nversion: \"3.7\"\n\nservices:\n  safeway-coupons:\n    image: ghcr.io/smkent/safeway-coupons:latest\n    environment:\n      CRON_SCHEDULE: \"0 2 * * *\"  # Run at 2:00 AM UTC each day\n      # TZ: Antarctica/McMurdo  # Optional time zone to use instead of UTC\n      SMTPHOST: your.smtp.host\n      SAFEWAY_ACCOUNT_USERNAME: your.safeway.account.email@example.com\n      SAFEWAY_ACCOUNT_PASSWORD: very_secret\n      SAFEWAY_ACCOUNT_MAIL_FROM: your.email@example.com\n      SAFEWAY_ACCOUNT_MAIL_TO: your.email@example.com\n      # EXTRA_ARGS: --debug  # Optional\n    restart: unless-stopped\n```\n\nExample `docker-compose.yaml` with configuration via accounts file:\n\n```yaml\nversion: \"3.7\"\n\nservices:\n  safeway-coupons:\n    image: ghcr.io/smkent/safeway-coupons:latest\n    environment:\n      CRON_SCHEDULE: \"0 2 * * *\"  # Run at 2:00 AM UTC each day\n      # TZ: Antarctica/McMurdo  # Optional time zone to use instead of UTC\n      SMTPHOST: your.smtp.host\n      SAFEWAY_ACCOUNTS_FILE: /accounts_file\n      # EXTRA_ARGS: --debug  # Optional\n    restart: unless-stopped\n    volumes:\n      - path/to/safeway_accounts_file:/accounts_file:ro\n```\n\nStart the container by running:\n\n```console\ndocker-compose up -d\n```\n\nDebugging information can be viewed in the container log:\n\n```console\ndocker-compose logs -f\n```\n\n## Installation from PyPI\n\n### Prerequisites\n\n* Google Chrome (for authentication performed via Selenium).\n* Optional: `sendmail` (for email support)\n\n### Installation\n\n[safeway-coupons is available on PyPI][pypi]:\n\n```console\npip install safeway-coupons\n```\n\n### Usage\n\nFor best results, run this program once a day or so with a cron daemon.\n\nFor full usage options, run\n\n```console\nsafeway-coupons --help\n```\n\n### Configuration\n\n**safeway-coupons** can clip coupons for one or more Safeway accounts in a\nsingle run, depending on the configuration method used.\n\nIf a sender email address is configured, a summary email will be sent for each\nSafeway account via `sendmail`. The email recipient defaults to the Safeway\naccount email address, but can be overridden for each account.\n\nAccounts are searched via the following methods in the listed order. Only one\naccount configuration method may be used at a time.\n\n#### With environment variables\n\nA single Safeway account can be configured with environment variables:\n\n* `SAFEWAY_ACCOUNT_USERNAME`: Account email address (required)\n* `SAFEWAY_ACCOUNT_PASSWORD`: Account password (required)\n* `SAFEWAY_ACCOUNT_MAIL_FROM`: Sender address for email summary\n* `SAFEWAY_ACCOUNT_MAIL_TO`: Recipient address for email summary\n\n#### With config file\n\nMultiple Safeway accounts can be provided in an ini-style config file, with a\nsection for each account. For example:\n\n```ini\nemail_sender = sender@example.com   ; optional\n\n[safeway.account@example.com]       ; required\npassword = 12345                    ; required\nnotify = your.email@example.com     ; optional\n```\n\nProvide the path to your config file using the `-c` or `--accounts-config`\noption:\n\n```console\nsafeway-coupons -c path/to/config/file\n```\n\n## Development\n\n### [Poetry][poetry] installation\n\nVia [`pipx`][pipx]:\n\n```console\npip install pipx\npipx install poetry\npipx inject poetry poetry-pre-commit-plugin\n```\n\nVia `pip`:\n\n```console\npip install poetry\npoetry self add poetry-pre-commit-plugin\n```\n\n### Invocation with docker-compose\n\nsafeway-coupons can be executed within a Docker container using\n`docker-compose.dev.yaml`.\n\nTo use, first create an `accounts` file in the same directory with your\nsafeway-coupons accounts configuration. Then, execute safeway-coupons within a\ncontainer using docker-compose:\n\n```console\ndocker-compose -f docker-compose.dev.yaml up --build\n```\n\nThe container will run safeway-coupons once, attempt to clip one coupon, and\nthen stop.\n\nTo change the safeway-coupons arguments, modify the `command` value in\n`docker-compose.dev.yaml`.\n\nWhen finished with development tasks, the docker-compose state can be cleaned up\nwith:\n\n```console\ndocker-compose -f docker-compose.dev.yaml down\n```\n\n### Development tasks\n\n* Setup: `poetry install`\n* Run static checks: `poetry run poe lint` or\n  `poetry run pre-commit run --all-files`\n* Run static checks and tests: `poetry run poe test`\n\n---\n\nCreated from [smkent/cookie-python][cookie-python] using\n[cookiecutter][cookiecutter]\n\n[codecov]: https://codecov.io/gh/smkent/safeway-coupons\n[cookie-python]: https://github.com/smkent/cookie-python\n[cookiecutter]: https://github.com/cookiecutter/cookiecutter\n[gh-actions]: https://github.com/smkent/safeway-coupons/actions?query=branch%3Amain\n[pipx]: https://pypa.github.io/pipx/\n[poetry]: https://python-poetry.org/docs/#installation\n[pypi]: https://pypi.org/project/safeway-coupons/\n[repo]: https://github.com/smkent/safeway-coupons\n[requests]: https://requests.readthedocs.io/en/latest/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmkent%2Fsafeway-coupons","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmkent%2Fsafeway-coupons","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmkent%2Fsafeway-coupons/lists"}