Giter Club home page Giter Club logo

camply's Introduction

camply, the campsite finder ⛺️, is a tool to help you book a campsite online. Finding reservations at sold out campgrounds can be tough. That's where camply comes in. It searches thousands of campgrounds across the USA world via the APIs of booking services like recreation.gov. It continuously checks for cancellations and availabilities to pop up - once a campsite becomes available, camply sends you a notification to book your spot!



PyPI PyPI - Python Version Docker Image Version Testing Status GitHub License Ruff pre-commit semantic-release Gitmoji Discord Chat

Installing

Install camply via pip or pipx:

pipx install camply

Usage

Search for a specific recreation area (recreation areas contain campgrounds):

camply recreation-areas --search "Glacier National Park"

Search for campgrounds (campgrounds contain campsites):

camply campgrounds --search "Fire Lookout Towers" --state CA

Search for available campsites, get a notification whenever one becomes available, and continue searching after the first one is found. The below command is using silent notifications as an example but camply also supports Email, Slack, Twilio (SMS), Pushover, Pushbullet, Ntfy, Apprise, Telegram, and Webhook.

camply campsites \
    --rec-area 2725 \
    --start-date 2023-07-10 \
    --end-date 2023-07-18 \
    --notifications silent \
    --search-forever

Providers

camply works with a number of providers. A "provider" is an online booking service that lists camping and recreation inventory.

Run camply providers to list current providers and visit the Providers section in the docs to learn more.

Documentation

Head over to the camply documentation to see what you can do!

camply --help

 Usage: camply [OPTIONS] COMMAND [ARGS]...

 Welcome to camply, the campsite finder.
 Finding reservations at sold out campgrounds can be tough. That's where camply comes in. It searches the
 APIs of booking services like https://recreation.gov (which indexes thousands of campgrounds across the
 USA) to continuously check for cancellations and availabilities to pop up. Once a campsite becomes
 available, camply sends you a notification to book your spot!


 visit the camply documentation at https://juftin.com/camply

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                        │
│  --debug/--no-debug             Enable extra debugging output                                          │
│  --provider              TEXT   Camping Search Provider. Defaults to 'RecreationDotGov'                │
│  --version                      Show the version and exit.                                             │
│  --help                         Show this message and exit.                                            │
│                                                                                                        │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                        │
│  campgrounds              Search for Campgrounds (inside of Recreation Areas) and list them            │
│  campsites                Find Available Campsites with Custom Search Criteria                         │
│  configure                Set up camply configuration file with an interactive console                 │
│  equipment-types          Get a list of supported equipment                                            │
│  list-campsites           List campsite IDs for a given campground or recreation area                  │
│  providers                List the different camply providers                                          │
│  recreation-areas         Search for Recreation Areas and list them                                    │
│  test-notifications       Test your notification provider setup                                        │
│  tui                      Open Textual TUI.                                                            │
│                                                                                                        │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Contributing

Camply doesn't support your favorite campsite booking provider yet? Consider contributing 😉.


Recreation data provided by Recreation.gov




juftin logo

camply's People

Contributors

acaloiaro avatar bhspitmonkey avatar damz avatar dependabot[bot] avatar dhuppenkothen avatar ethan-leba avatar gaelollivier avatar github-actions[bot] avatar jingyuanliang avatar juftin avatar matthazinski avatar melroy89 avatar regaw-leinad avatar semantic-release-bot avatar septikus avatar stjohnjohnson avatar thornto4 avatar willcohen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

camply's Issues

List Providers

Describe the solution you'd like

Finding the different providers is clunky, you should be able to list providers from the command line

Going-to-camp provider campground listing not working

Describe the bug
Receiving bad data from GoingtoCamp API

Original Camply Command (with --debug)

camply campgrounds --debug --provider goingtocamp --rec-area 3

Expected behavior
< A clear and concise description of what you expected to happen. >

Console Output (with --debug)

chuping@Chupings-Air ~ % camply campgrounds --debug --provider goingtocamp --rec-area 3
[2023-04-04 11:46:58] CAMPLY   camply, the campsite finder ⛺️                                                                                                                                               
[2023-04-04 11:46:58] INFO     Using Camply Provider: "GoingToCamp"                                                                                                                                         
[2023-04-04 11:46:58] DEBUG    Setting up camply debugging                                                                                                                                                  
[2023-04-04 11:46:58] DEBUG    Camply Version: 0.16.0                                                                                                                                                       
[2023-04-04 11:46:58] DEBUG    Python Version: 3.9.6                                                                                                                                                        
[2023-04-04 11:46:58] DEBUG    Platform: darwin                                                                                                                                                             
[2023-04-04 11:46:58] INFO     Retrieving Facility Information for Recreation Area ID: `3`.                                                                                                                 
[2023-04-04 11:46:58] DEBUG    Starting new HTTPS connection (1): washington.goingtocamp.com:443                                                                                                            
[2023-04-04 11:46:58] DEBUG    https://washington.goingtocamp.com:443 "GET /api/resourcelocation/rootmaps HTTP/1.1" 404 0                                                                                   
[2023-04-04 11:46:58] ERROR    Receiving bad data from GoingToCamp API: status_code:                                                                                                                        
[2023-04-04 11:46:58] CAMPLY   Exiting camply 👋                                                                                                                                                            
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/chuping/Library/Python/3.9/bin/camply:8 in <module>                                       │
│                                                                                                  │
│   5 from camply.cli import cli                                                                   │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(cli())                                                                          │
│   9                                                                                              │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ cli = <function cli at 0x1289f98b0>                                                          │ │
│ │  re = <module 're' from                                                                      │ │
│ │       '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.… │ │
│ │ sys = <module 'sys' (built-in)>                                                              │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/camply/cli.py:750 in cli              │
│                                                                                                  │
│   747 │   Camply Command Line Utility Wrapper                                                    │
│   748 │   """                                                                                    │
│   749 │   try:                                                                                   │
│ ❱ 750 │   │   camply_command_line()                                                              │
│   751 │   except KeyboardInterrupt:                                                              │
│   752 │   │   logger.debug("Handling Exit Request")                                              │
│   753 │   finally:                                                                               │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/core.py:1130 in __call__        │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/rich_click/rich_group.py:21 in main   │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/core.py:1055 in main            │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/core.py:1657 in invoke          │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/core.py:1404 in invoke          │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/core.py:760 in invoke           │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/click/decorators.py:38 in new_func    │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/camply/cli.py:311 in campgrounds      │
│                                                                                                  │
│   308 │   params = {}                                                                            │
│   309 │   if state is not None:                                                                  │
│   310 │   │   params.update({"state": state})                                                    │
│ ❱ 311 │   camp_finder.find_campgrounds(                                                          │
│   312 │   │   search_string=search,                                                              │
│   313 │   │   rec_area_id=make_list(rec_area, coerce=int),                                       │
│   314 │   │   campground_id=make_list(campground, coerce=int),                                   │
│                                                                                                  │
│ ╭──────────────────────────────────────── locals ────────────────────────────────────────╮       │
│ │           camp_finder = <GoingToCampProvider>                                          │       │
│ │            campground = ()                                                             │       │
│ │              campsite = ()                                                             │       │
│ │               context = CamplyContext(debug=True, provider=None)                       │       │
│ │                 debug = True                                                           │       │
│ │                params = {}                                                             │       │
│ │              provider = 'GoingToCamp'                                                  │       │
│ │              rec_area = ('3',)                                                         │       │
│ │                search = None                                                           │       │
│ │ search_provider_class = <class 'camply.search.search_going_to_camp.SearchGoingToCamp'> │       │
│ │                 state = None                                                           │       │
│ ╰────────────────────────────────────────────────────────────────────────────────────────╯       │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/camply/providers/going_to_camp/going_ │
│ to_camp_provider.py:208 in find_campgrounds                                                      │
│                                                                                                  │
│   205 │   │   │   )                                                                              │
│   206 │   │   │   sys.exit(1)                                                                    │
│   207 │   │                                                                                      │
│ ❱ 208 │   │   return self.find_facilities_per_recreation_area(                                   │
│   209 │   │   │   rec_area_id=rec_area_id,                                                       │
│   210 │   │   │   campground_id=campground_id,                                                   │
│   211 │   │   │   searching_string=search_string,                                                │
│                                                                                                  │
│ ╭─────────────── locals ────────────────╮                                                        │
│ │ campground_id = []                    │                                                        │
│ │   campsite_id = []                    │                                                        │
│ │        kwargs = {}                    │                                                        │
│ │   rec_area_id = ['3']                 │                                                        │
│ │ search_string = None                  │                                                        │
│ │          self = <GoingToCampProvider> │                                                        │
│ ╰───────────────────────────────────────╯                                                        │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/camply/providers/going_to_camp/going_ │
│ to_camp_provider.py:355 in find_facilities_per_recreation_area                                   │
│                                                                                                  │
│   352 │   │   │   sys.exit(1)                                                                    │
│   353 │   │                                                                                      │
│   354 │   │   self.campground_details = {}                                                       │
│ ❱ 355 │   │   api_response = self._api_request(rec_area_id, "LIST_CAMPGROUNDS")                  │
│   356 │   │                                                                                      │
│   357 │   │   filtered_facilities = self._filter_facilities_responses(                           │
│   358 │   │   │   rec_area_id, facilities=api_response                                           │
│                                                                                                  │
│ ╭─────────────────────────────── locals ───────────────────────────────╮                         │
│ │             _ = 'camping.bcparks.ca'                                 │                         │
│ │ campground_id = []                                                   │                         │
│ │        kwargs = {'searching_string': None}                           │                         │
│ │            ra = RecreationArea(                                      │                         │
│ │                 │   recreation_area='BC Parks',                      │                         │
│ │                 │   recreation_area_id=12,                           │                         │
│ │                 │   recreation_area_location='British Columbia, CA', │                         │
│ │                 │   coordinates=None,                                │                         │
│ │                 │   description=None                                 │                         │
│ │                 )                                                    │                         │
│ │      rec_area = RecreationArea(                                      │                         │
│ │                 │   recreation_area='Washington State Parks',        │                         │
│ │                 │   recreation_area_id=3,                            │                         │
│ │                 │   recreation_area_location='Washington, USA',      │                         │
│ │                 │   coordinates=None,                                │                         │
│ │                 │   description=None                                 │                         │
│ │                 )                                                    │                         │
│ │   rec_area_id = '3'                                                  │                         │
│ │ search_string = None                                                 │                         │
│ │          self = <GoingToCampProvider>                                │                         │
│ ╰──────────────────────────────────────────────────────────────────────╯                         │
│                                                                                                  │
│ /Users/chuping/Library/Python/3.9/lib/python/site-packages/camply/providers/going_to_camp/going_ │
│ to_camp_provider.py:418 in _api_request                                                          │
│                                                                                                  │
│   415 │   │   │   error_message = "Receiving bad data from GoingToCamp API: status_code: "       │
│   416 │   │   │   f"{response.status_code}: {response.text}"                                     │
│   417 │   │   │   logger.error(error_message)                                                    │
│ ❱ 418 │   │   │   raise ConnectionError(error_message)                                           │
│   419 │   │                                                                                      │
│   420 │   │   return json.loads(response.content)                                                │
│   421                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │      endpoint = 'https://{}/api/resourcelocation/rootmaps'                                   │ │
│ │ endpoint_name = 'LIST_CAMPGROUNDS'                                                           │ │
│ │ error_message = 'Receiving bad data from GoingToCamp API: status_code: '                     │ │
│ │      hostname = 'washington.goingtocamp.com'                                                 │ │
│ │        params = {}                                                                           │ │
│ │   rec_area_id = '3'                                                                          │ │
│ │      response = <Response [404]>                                                             │ │
│ │          self = <GoingToCampProvider>                                                        │ │
│ │           url = 'https://washington.goingtocamp.com/api/resourcelocation/rootmaps'           │ │
│ │    user_agent = {                                                                            │ │
│ │                 │   'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML,   │ │
│ │                 like Gecko) Chrome/12.0.'+19                                                 │ │
│ │                 }                                                                            │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ConnectionError: Receiving bad data from GoingToCamp API: status_code: 

Additional context

< Add any other context about the problem here. >

Issue with multiple campsite search?

Hi! I'm getting this error when I try to search multiple campsites, either through a .yml file or through the command line. Single campsite searches seem to work fine, as does your example .yml with multiple rec areas. I'm not sure how it got pointed to my Dropbox folder (which is where I was running camply from) to search for pydantic ... and am not good enough at scanning the code to pinpoint the line but it seems like a bug?
error.txt

Gmail login is not supported anymore

Describe the bug

Sending email via Gmail might not be a viable method anymore, cause Google recently updated their policy and banned logging in from vulnerable resources. More info: here.

Reserve California doesn't work for me.

Describe the bug

When attempting to fetch campsites from the provider "ReserveCalifornia" using the camply campsites command a KeyError is thrown, specifically "KeyError: 'reservecalifornia' ". It appears that the software is unable to correctly process the specified provider name.

Original Camply Command (with --debug)

camply --debug campsites \
    --provider ReserveCalifornia \
    --campground 641 \
    --start-date 2023-08-30 \
    --end-date 2023-09-01 \
    --nights 2 \
    --notifications pushover \
    --polling-interval 5 \
    --search-forever \
    --continuous

Expected behavior
<I expected the program to fetch available campsites for the specified campground (641) from the ReserveCalifornia provider for the specified date range. It should then continuously monitor for availability at this campground and notify via Pushover whenever availability is found.. >

Console Output (with --debug)

<With debug:  Error: no such option: --debug>
<Without debug:  KeyError: 'reservecalifornia'>

Additional context

< Add any other context about the problem here. >

TypeError: 'NoneType' object is not iterable

This is my search:

provider: Yellowstone
recreation_area:
campgrounds: YLYF:RV
start_date: 2023-06-05
end_date: 2023-06-30 D
nights: 3
continuous: True
polling_interval: 5
notifications: pushover
search_forever: True
notify_first_try: True

Which causes this error:

camply-docker-compose-fishing-bridge | TypeError: 'NoneType' object is not iterable
camply-docker-compose-fishing-bridge exited with code 1

This search used to work. All I changed was the dsate range.

Did something in the code change?

Thanks!

camply-docker-compose-fishing-bridge | start ----------------------
camply-docker-compose-fishing-bridge | ----------------------
camply-docker-compose-fishing-bridge | HOSTNAME=ec68bcbe4d94
camply-docker-compose-fishing-bridge | PYTHON_VERSION=3.9.13
camply-docker-compose-fishing-bridge | CAMPLY_LOG_HANDLER=PYTHON
camply-docker-compose-fishing-bridge | PWD=/home/ec2-user
camply-docker-compose-fishing-bridge | PYTHON_SETUPTOOLS_VERSION=58.1.0
camply-docker-compose-fishing-bridge | TZ=America/Denver
camply-docker-compose-fishing-bridge | HOME=/home/camply
camply-docker-compose-fishing-bridge | LANG=C.UTF-8
camply-docker-compose-fishing-bridge | GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568
camply-docker-compose-fishing-bridge | SHLVL=1
camply-docker-compose-fishing-bridge | PYTHON_PIP_VERSION=22.0.4
camply-docker-compose-fishing-bridge | PYTHON_GET_PIP_SHA256=5aefe6ade911d997af080b315ebcb7f882212d070465df544e1175ac2be519b4
camply-docker-compose-fishing-bridge | PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/5eaac1050023df1f5c98b173b248c260023f2278/public/get-pip.py
camply-docker-compose-fishing-bridge | PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
camply-docker-compose-fishing-bridge | _=/usr/bin/printenv
camply-docker-compose-fishing-bridge | ----------------------
camply-docker-compose-fishing-bridge | camply
camply-docker-compose-fishing-bridge | ec2-user
camply-docker-compose-fishing-bridge | ----------------------
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,719 [ CAMPLY]: camply, the campsite finder ⛺️
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,723 [ INFO]: YAML File Parsed: search.yml
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,725 [ INFO]: 25 booking nights selected for search, ranging from 2023-06-05 to 2023-06-29
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,735 [ INFO]: Searching for availabilities with 3 consecutive night stays.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,736 [ INFO]: Searching for campsites every 5 minutes.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,736 [ INFO]: Notifications active via: ,
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,737 [ INFO]: 1 Matching Campgrounds Found
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,737 [ INFO]: ⛰ Yellowstone National Park, USA (#1) - 🏕 Fishing Bridge RV Park (YLYF:RV)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:04,757 [ INFO]: Searching for Yellowstone Lodging Availability: June, 2023
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:06,954 [ INFO]: ⛺️ 139 sites found.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,186 [ INFO]: ⛺️ ⛺️ ⛺️ ⛺️ 25 Reservable Campsites Matching Search Preferences
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,193 [ INFO]: 📅 Sat, June 03 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,196 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,197 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-03-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,197 [ INFO]: 📅 Sun, June 04 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,199 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,200 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-04-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,201 [ INFO]: 📅 Mon, June 05 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,202 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,203 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-05-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,204 [ INFO]: 📅 Tue, June 06 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,205 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,207 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-06-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,207 [ INFO]: 📅 Wed, June 07 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,208 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,210 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-07-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,210 [ INFO]: 📅 Thu, June 08 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,212 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,213 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-08-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,213 [ INFO]: 📅 Fri, June 09 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,215 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,216 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-09-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,217 [ INFO]: 📅 Sat, June 10 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,218 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,219 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-10-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,220 [ INFO]: 📅 Sun, June 11 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,221 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,223 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-11-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,223 [ INFO]: 📅 Mon, June 12 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,225 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,226 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-12-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,227 [ INFO]: 📅 Fri, June 16 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,228 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,229 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-16-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,230 [ INFO]: 📅 Wed, June 21 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,231 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,233 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-21-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,233 [ INFO]: 📅 Thu, June 22 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,235 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,236 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-22-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,237 [ INFO]: 📅 Fri, June 23 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,238 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,239 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-23-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,240 [ INFO]: 📅 Sat, June 24 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,241 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,243 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-24-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,243 [ INFO]: 📅 Sun, June 25 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,245 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,246 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-25-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,246 [ INFO]: 📅 Mon, June 26 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,248 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,249 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-26-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,250 [ INFO]: 📅 Tue, June 27 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,251 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,252 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-27-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,253 [ INFO]: 25 New Campsites Found.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,253 [ WARNING]: Too many campsites were found during the search (25 total). camply will only send you the first 20 notifications.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:23,372 [ CAMPLY]: Exiting camply 👋
camply-docker-compose-fishing-bridge | ╭───────────────────── Traceback (most recent call last) ──────────────────────╮
camply-docker-compose-fishing-bridge | │ /usr/local/bin/camply:8 in │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 5 from camply.cli import cli │
camply-docker-compose-fishing-bridge | │ 6 if name == 'main': │
camply-docker-compose-fishing-bridge | │ 7 │ sys.argv[0] = re.sub(r'(-script.pyw|.exe)?$', '', sys.argv[0]) │
camply-docker-compose-fishing-bridge | │ ❱ 8 │ sys.exit(cli()) │
camply-docker-compose-fishing-bridge | │ 9 │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/cli.py:429 in cli │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 426 │ Camply Command Line Utility Wrapper │
camply-docker-compose-fishing-bridge | │ 427 │ """ │
camply-docker-compose-fishing-bridge | │ 428 │ try: │
camply-docker-compose-fishing-bridge | │ ❱ 429 │ │ camply_command_line() │
camply-docker-compose-fishing-bridge | │ 430 │ except KeyboardInterrupt: │
camply-docker-compose-fishing-bridge | │ 431 │ │ logger.debug("Handling Exit Request") │
camply-docker-compose-fishing-bridge | │ 432 │ finally: │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1130 in call
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1127 │ │
camply-docker-compose-fishing-bridge | │ 1128 │ def call(self, *args: t.Any, **kwargs: t.Any) -> t.Any: │
camply-docker-compose-fishing-bridge | │ 1129 │ │ """Alias for :meth:main.""" │
camply-docker-compose-fishing-bridge | │ ❱ 1130 │ │ return self.main(*args, **kwargs) │
camply-docker-compose-fishing-bridge | │ 1131 │
camply-docker-compose-fishing-bridge | │ 1132 │
camply-docker-compose-fishing-bridge | │ 1133 class Command(BaseCommand): │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1055 in main │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1052 │ │ try: │
camply-docker-compose-fishing-bridge | │ 1053 │ │ │ try: │
camply-docker-compose-fishing-bridge | │ 1054 │ │ │ │ with self.make_context(prog_name, args, **extra) as c │
camply-docker-compose-fishing-bridge | │ ❱ 1055 │ │ │ │ │ rv = self.invoke(ctx) │
camply-docker-compose-fishing-bridge | │ 1056 │ │ │ │ │ if not standalone_mode: │
camply-docker-compose-fishing-bridge | │ 1057 │ │ │ │ │ │ return rv │
camply-docker-compose-fishing-bridge | │ 1058 │ │ │ │ │ # it's not safe to ctx.exit(rv) here! │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1657 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1654 │ │ │ │ super().invoke(ctx) │
camply-docker-compose-fishing-bridge | │ 1655 │ │ │ │ sub_ctx = cmd.make_context(cmd_name, args, parent=ctx │
camply-docker-compose-fishing-bridge | │ 1656 │ │ │ │ with sub_ctx: │
camply-docker-compose-fishing-bridge | │ ❱ 1657 │ │ │ │ │ return _process_result(sub_ctx.command.invoke(sub │
camply-docker-compose-fishing-bridge | │ 1658 │ │ │
camply-docker-compose-fishing-bridge | │ 1659 │ │ # In chain mode we create the contexts step by step, but afte │
camply-docker-compose-fishing-bridge | │ 1660 │ │ # base command has been invoked. Because at that point we do │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1404 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1401 │ │ │ echo(style(message, fg="red"), err=True) │
camply-docker-compose-fishing-bridge | │ 1402 │ │ │
camply-docker-compose-fishing-bridge | │ 1403 │ │ if self.callback is not None: │
camply-docker-compose-fishing-bridge | │ ❱ 1404 │ │ │ return ctx.invoke(self.callback, **ctx.params) │
camply-docker-compose-fishing-bridge | │ 1405 │ │
camply-docker-compose-fishing-bridge | │ 1406 │ def shell_complete(self, ctx: Context, incomplete: str) -> t.List │
camply-docker-compose-fishing-bridge | │ 1407 │ │ """Return a list of completions for the incomplete value. Loo │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:760 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 757 │ │ │
camply-docker-compose-fishing-bridge | │ 758 │ │ with augment_usage_errors(__self): │
camply-docker-compose-fishing-bridge | │ 759 │ │ │ with ctx: │
camply-docker-compose-fishing-bridge | │ ❱ 760 │ │ │ │ return __callback(*args, **kwargs) │
camply-docker-compose-fishing-bridge | │ 761 │ │
camply-docker-compose-fishing-bridge | │ 762 │ def forward( │
camply-docker-compose-fishing-bridge | │ 763 │ │ __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # no │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/cli.py:421 in campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 418 │ │ key.lower(): value for key, value in CAMPSITE_SEARCH_PROVIDER. │
camply-docker-compose-fishing-bridge | │ 419 │ }[provider.lower()] │
camply-docker-compose-fishing-bridge | │ 420 │ camping_finder = provider_class(**provider_kwargs) │
camply-docker-compose-fishing-bridge | │ ❱ 421 │ camping_finder.get_matching_campsites(**search_kwargs) │
camply-docker-compose-fishing-bridge | │ 422 │
camply-docker-compose-fishing-bridge | │ 423 │
camply-docker-compose-fishing-bridge | │ 424 def cli(): │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:468 in │
camply-docker-compose-fishing-bridge | │ get_matching_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 465 │ │ List[AvailableCampsite] │
camply-docker-compose-fishing-bridge | │ 466 │ │ """ │
camply-docker-compose-fishing-bridge | │ 467 │ │ if continuous is True: │
camply-docker-compose-fishing-bridge | │ ❱ 468 │ │ │ self._search_campsites_continuous( │
camply-docker-compose-fishing-bridge | │ 469 │ │ │ │ log=log, │
camply-docker-compose-fishing-bridge | │ 470 │ │ │ │ verbose=verbose, │
camply-docker-compose-fishing-bridge | │ 471 │ │ │ │ polling_interval=polling_interval, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:412 in │
camply-docker-compose-fishing-bridge | │ _search_campsites_continuous │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 409 │ │ continuous_search = True │
camply-docker-compose-fishing-bridge | │ 410 │ │ continuous_search_attempts = 1 │
camply-docker-compose-fishing-bridge | │ 411 │ │ while continuous_search is True: │
camply-docker-compose-fishing-bridge | │ ❱ 412 │ │ │ self._continuous_search_retry( │
camply-docker-compose-fishing-bridge | │ 413 │ │ │ │ log=log, │
camply-docker-compose-fishing-bridge | │ 414 │ │ │ │ verbose=verbose, │
camply-docker-compose-fishing-bridge | │ 415 │ │ │ │ polling_interval=polling_interval, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:276 in │
camply-docker-compose-fishing-bridge | │ _continuous_search_retry │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 273 │ │ logger.info(f"{len(new_campsites)} New Campsites Found.") │
camply-docker-compose-fishing-bridge | │ 274 │ │ self.campsites_found.update(new_campsites) │
camply-docker-compose-fishing-bridge | │ 275 │ │ logged_campsites = list(new_campsites) │
camply-docker-compose-fishing-bridge | │ ❱ 276 │ │ self._handle_notifications( │
camply-docker-compose-fishing-bridge | │ 277 │ │ │ retryer=retryer, │
camply-docker-compose-fishing-bridge | │ 278 │ │ │ notifier=notifier, │
camply-docker-compose-fishing-bridge | │ 279 │ │ │ logged_campsites=logged_campsites, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:320 in │
camply-docker-compose-fishing-bridge | │ _handle_notifications │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 317 │ │ │ logged_campsites = cls.handle_too_many_campsites_found( │
camply-docker-compose-fishing-bridge | │ 318 │ │ │ │ notifier=notifier, logged_campsites=logged_campsites │
camply-docker-compose-fishing-bridge | │ 319 │ │ │ ) │
camply-docker-compose-fishing-bridge | │ ❱ 320 │ │ │ notifier.send_campsites(campsites=logged_campsites) │
camply-docker-compose-fishing-bridge | │ 321 │ │ else: │
camply-docker-compose-fishing-bridge | │ 322 │ │ │ if ( │
camply-docker-compose-fishing-bridge | │ 323 │ │ │ │ len(notifier.providers) > 1 │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/multi_provider_n │
camply-docker-compose-fishing-bridge | │ otifications.py:84 in send_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 81 │ │ campsites: List[AvailableCampsite] │
camply-docker-compose-fishing-bridge | │ 82 │ │ """ │
camply-docker-compose-fishing-bridge | │ 83 │ │ for provider in self.providers: │
camply-docker-compose-fishing-bridge | │ ❱ 84 │ │ │ provider.send_campsites(campsites=campsites, **kwargs) │
camply-docker-compose-fishing-bridge | │ 85 │ │
camply-docker-compose-fishing-bridge | │ 86 │ def log_providers(self) -> None: │
camply-docker-compose-fishing-bridge | │ 87 │ │ """ │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/pushover.py:104 │
camply-docker-compose-fishing-bridge | │ in send_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 101 │ │ campsites: AvailableCampsite │
camply-docker-compose-fishing-bridge | │ 102 │ │ """ │
camply-docker-compose-fishing-bridge | │ 103 │ │ for campsite in campsites: │
camply-docker-compose-fishing-bridge | │ ❱ 104 │ │ │ message_title, formatted_dict = cls.format_standard_campsi │
camply-docker-compose-fishing-bridge | │ 105 │ │ │ │ campsite=campsite, │
camply-docker-compose-fishing-bridge | │ 106 │ │ │ ) │
camply-docker-compose-fishing-bridge | │ 107 │ │ │ fields = [] │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/base_notificatio │
camply-docker-compose-fishing-bridge | │ ns.py:79 in format_standard_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 76 │ │ │ │ key = "booking_link" │
camply-docker-compose-fishing-bridge | │ 77 │ │ │ elif key == CampsiteContainerFields.PERMITTED_EQUIPMENT: │
camply-docker-compose-fishing-bridge | │ 78 │ │ │ │ value = "\n - " + "\n - ".join( │
camply-docker-compose-fishing-bridge | │ ❱ 79 │ │ │ │ │ set(item.equipment_name for item in campsite.permit │
camply-docker-compose-fishing-bridge | │ 80 │ │ │ │ ) │
camply-docker-compose-fishing-bridge | │ 81 │ │ │ if key not in [CampsiteContainerFields.CAMPSITE_ATTRIBUTES] │
camply-docker-compose-fishing-bridge | │ 82 │ │ │ │ formatted_key = key.replace("
", " ").title() │
camply-docker-compose-fishing-bridge | ╰──────────────────────────────────────────────────────────────────────────────╯
camply-docker-compose-fishing-bridge | TypeError: 'NoneType' object is not iterable
camply-docker-compose-fishing-bridge exited with code 1
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,385 [ CAMPLY]: camply, the campsite finder ⛺️
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,388 [ INFO]: YAML File Parsed: search.yml
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,390 [ INFO]: 25 booking nights selected for search, ranging from 2023-06-05 to 2023-06-29
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,392 [ INFO]: Searching for availabilities with 3 consecutive night stays.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,393 [ INFO]: Searching for campsites every 5 minutes.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,393 [ INFO]: Notifications active via: ,
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,393 [ INFO]: 1 Matching Campgrounds Found
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,394 [ INFO]: ⛰ Yellowstone National Park, USA (#1) - 🏕 Fishing Bridge RV Park (YLYF:RV)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:25,413 [ INFO]: Searching for Yellowstone Lodging Availability: June, 2023
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:27,982 [ INFO]: ⛺️ 139 sites found.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,621 [ INFO]: ⛺️ ⛺️ ⛺️ ⛺️ 25 Reservable Campsites Matching Search Preferences
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,627 [ INFO]: 📅 Sat, June 03 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,629 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,630 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-03-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,630 [ INFO]: 📅 Sun, June 04 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,632 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,633 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-04-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,633 [ INFO]: 📅 Mon, June 05 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,635 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,636 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-05-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,637 [ INFO]: 📅 Tue, June 06 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,638 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,639 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-06-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,640 [ INFO]: 📅 Wed, June 07 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,641 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,642 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-07-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,643 [ INFO]: 📅 Thu, June 08 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,644 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,645 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-08-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,646 [ INFO]: 📅 Fri, June 09 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,647 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,648 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-09-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,649 [ INFO]: 📅 Sat, June 10 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,650 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,651 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-10-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,652 [ INFO]: 📅 Sun, June 11 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,653 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,654 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-11-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,655 [ INFO]: 📅 Mon, June 12 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,656 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,657 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-12-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,658 [ INFO]: 📅 Fri, June 16 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,659 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,660 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-16-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,661 [ INFO]: 📅 Wed, June 21 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,662 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,663 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-21-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,664 [ INFO]: 📅 Thu, June 22 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,665 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,667 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-22-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,667 [ INFO]: 📅 Fri, June 23 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,668 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,670 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-23-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,670 [ INFO]: 📅 Sat, June 24 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,672 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,673 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-24-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,673 [ INFO]: 📅 Sun, June 25 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,675 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,676 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-25-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,677 [ INFO]: 📅 Mon, June 26 🏕 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,678 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 1 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,679 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-26-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,680 [ INFO]: 📅 Tue, June 27 🏕 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,681 [ INFO]: ⛰️ Yellowstone 🏕 Fishing Bridge RV Internet Rate: ⛺ 2 sites
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,682 [ INFO]: 🔗 https://secure.yellowstonenationalparklodges.com/booking/lodging-select?dateFrom=06-27-2023&adults=1&destination=YLYF%3ARV&children=0&nights=3 (3 nights)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,683 [ INFO]: 25 New Campsites Found.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,683 [ WARNING]: Too many campsites were found during the search (25 total). camply will only send you the first 20 notifications.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:44,799 [ CAMPLY]: Exiting camply 👋
camply-docker-compose-fishing-bridge | ╭───────────────────── Traceback (most recent call last) ──────────────────────╮
camply-docker-compose-fishing-bridge | │ /usr/local/bin/camply:8 in │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 5 from camply.cli import cli │
camply-docker-compose-fishing-bridge | │ 6 if name == 'main': │
camply-docker-compose-fishing-bridge | │ 7 │ sys.argv[0] = re.sub(r'(-script.pyw|.exe)?$', '', sys.argv[0]) │
camply-docker-compose-fishing-bridge | │ ❱ 8 │ sys.exit(cli()) │
camply-docker-compose-fishing-bridge | │ 9 │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/cli.py:429 in cli │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 426 │ Camply Command Line Utility Wrapper │
camply-docker-compose-fishing-bridge | │ 427 │ """ │
camply-docker-compose-fishing-bridge | │ 428 │ try: │
camply-docker-compose-fishing-bridge | │ ❱ 429 │ │ camply_command_line() │
camply-docker-compose-fishing-bridge | │ 430 │ except KeyboardInterrupt: │
camply-docker-compose-fishing-bridge | │ 431 │ │ logger.debug("Handling Exit Request") │
camply-docker-compose-fishing-bridge | │ 432 │ finally: │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1130 in call
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1127 │ │
camply-docker-compose-fishing-bridge | │ 1128 │ def call(self, *args: t.Any, **kwargs: t.Any) -> t.Any: │
camply-docker-compose-fishing-bridge | │ 1129 │ │ """Alias for :meth:main.""" │
camply-docker-compose-fishing-bridge | │ ❱ 1130 │ │ return self.main(*args, **kwargs) │
camply-docker-compose-fishing-bridge | │ 1131 │
camply-docker-compose-fishing-bridge | │ 1132 │
camply-docker-compose-fishing-bridge | │ 1133 class Command(BaseCommand): │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1055 in main │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1052 │ │ try: │
camply-docker-compose-fishing-bridge | │ 1053 │ │ │ try: │
camply-docker-compose-fishing-bridge | │ 1054 │ │ │ │ with self.make_context(prog_name, args, **extra) as c │
camply-docker-compose-fishing-bridge | │ ❱ 1055 │ │ │ │ │ rv = self.invoke(ctx) │
camply-docker-compose-fishing-bridge | │ 1056 │ │ │ │ │ if not standalone_mode: │
camply-docker-compose-fishing-bridge | │ 1057 │ │ │ │ │ │ return rv │
camply-docker-compose-fishing-bridge | │ 1058 │ │ │ │ │ # it's not safe to ctx.exit(rv) here! │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1657 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1654 │ │ │ │ super().invoke(ctx) │
camply-docker-compose-fishing-bridge | │ 1655 │ │ │ │ sub_ctx = cmd.make_context(cmd_name, args, parent=ctx │
camply-docker-compose-fishing-bridge | │ 1656 │ │ │ │ with sub_ctx: │
camply-docker-compose-fishing-bridge | │ ❱ 1657 │ │ │ │ │ return _process_result(sub_ctx.command.invoke(sub │
camply-docker-compose-fishing-bridge | │ 1658 │ │ │
camply-docker-compose-fishing-bridge | │ 1659 │ │ # In chain mode we create the contexts step by step, but afte │
camply-docker-compose-fishing-bridge | │ 1660 │ │ # base command has been invoked. Because at that point we do │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:1404 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 1401 │ │ │ echo(style(message, fg="red"), err=True) │
camply-docker-compose-fishing-bridge | │ 1402 │ │ │
camply-docker-compose-fishing-bridge | │ 1403 │ │ if self.callback is not None: │
camply-docker-compose-fishing-bridge | │ ❱ 1404 │ │ │ return ctx.invoke(self.callback, **ctx.params) │
camply-docker-compose-fishing-bridge | │ 1405 │ │
camply-docker-compose-fishing-bridge | │ 1406 │ def shell_complete(self, ctx: Context, incomplete: str) -> t.List │
camply-docker-compose-fishing-bridge | │ 1407 │ │ """Return a list of completions for the incomplete value. Loo │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/click/core.py:760 in invoke │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 757 │ │ │
camply-docker-compose-fishing-bridge | │ 758 │ │ with augment_usage_errors(__self): │
camply-docker-compose-fishing-bridge | │ 759 │ │ │ with ctx: │
camply-docker-compose-fishing-bridge | │ ❱ 760 │ │ │ │ return __callback(*args, **kwargs) │
camply-docker-compose-fishing-bridge | │ 761 │ │
camply-docker-compose-fishing-bridge | │ 762 │ def forward( │
camply-docker-compose-fishing-bridge | │ 763 │ │ __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # no │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/cli.py:421 in campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 418 │ │ key.lower(): value for key, value in CAMPSITE_SEARCH_PROVIDER. │
camply-docker-compose-fishing-bridge | │ 419 │ }[provider.lower()] │
camply-docker-compose-fishing-bridge | │ 420 │ camping_finder = provider_class(**provider_kwargs) │
camply-docker-compose-fishing-bridge | │ ❱ 421 │ camping_finder.get_matching_campsites(**search_kwargs) │
camply-docker-compose-fishing-bridge | │ 422 │
camply-docker-compose-fishing-bridge | │ 423 │
camply-docker-compose-fishing-bridge | │ 424 def cli(): │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:468 in │
camply-docker-compose-fishing-bridge | │ get_matching_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 465 │ │ List[AvailableCampsite] │
camply-docker-compose-fishing-bridge | │ 466 │ │ """ │
camply-docker-compose-fishing-bridge | │ 467 │ │ if continuous is True: │
camply-docker-compose-fishing-bridge | │ ❱ 468 │ │ │ self._search_campsites_continuous( │
camply-docker-compose-fishing-bridge | │ 469 │ │ │ │ log=log, │
camply-docker-compose-fishing-bridge | │ 470 │ │ │ │ verbose=verbose, │
camply-docker-compose-fishing-bridge | │ 471 │ │ │ │ polling_interval=polling_interval, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:412 in │
camply-docker-compose-fishing-bridge | │ _search_campsites_continuous │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 409 │ │ continuous_search = True │
camply-docker-compose-fishing-bridge | │ 410 │ │ continuous_search_attempts = 1 │
camply-docker-compose-fishing-bridge | │ 411 │ │ while continuous_search is True: │
camply-docker-compose-fishing-bridge | │ ❱ 412 │ │ │ self._continuous_search_retry( │
camply-docker-compose-fishing-bridge | │ 413 │ │ │ │ log=log, │
camply-docker-compose-fishing-bridge | │ 414 │ │ │ │ verbose=verbose, │
camply-docker-compose-fishing-bridge | │ 415 │ │ │ │ polling_interval=polling_interval, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:276 in │
camply-docker-compose-fishing-bridge | │ _continuous_search_retry │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 273 │ │ logger.info(f"{len(new_campsites)} New Campsites Found.") │
camply-docker-compose-fishing-bridge | │ 274 │ │ self.campsites_found.update(new_campsites) │
camply-docker-compose-fishing-bridge | │ 275 │ │ logged_campsites = list(new_campsites) │
camply-docker-compose-fishing-bridge | │ ❱ 276 │ │ self._handle_notifications( │
camply-docker-compose-fishing-bridge | │ 277 │ │ │ retryer=retryer, │
camply-docker-compose-fishing-bridge | │ 278 │ │ │ notifier=notifier, │
camply-docker-compose-fishing-bridge | │ 279 │ │ │ logged_campsites=logged_campsites, │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:320 in │
camply-docker-compose-fishing-bridge | │ _handle_notifications │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 317 │ │ │ logged_campsites = cls.handle_too_many_campsites_found( │
camply-docker-compose-fishing-bridge | │ 318 │ │ │ │ notifier=notifier, logged_campsites=logged_campsites │
camply-docker-compose-fishing-bridge | │ 319 │ │ │ ) │
camply-docker-compose-fishing-bridge | │ ❱ 320 │ │ │ notifier.send_campsites(campsites=logged_campsites) │
camply-docker-compose-fishing-bridge | │ 321 │ │ else: │
camply-docker-compose-fishing-bridge | │ 322 │ │ │ if ( │
camply-docker-compose-fishing-bridge | │ 323 │ │ │ │ len(notifier.providers) > 1 │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/multi_provider_n │
camply-docker-compose-fishing-bridge | │ otifications.py:84 in send_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 81 │ │ campsites: List[AvailableCampsite] │
camply-docker-compose-fishing-bridge | │ 82 │ │ """ │
camply-docker-compose-fishing-bridge | │ 83 │ │ for provider in self.providers: │
camply-docker-compose-fishing-bridge | │ ❱ 84 │ │ │ provider.send_campsites(campsites=campsites, **kwargs) │
camply-docker-compose-fishing-bridge | │ 85 │ │
camply-docker-compose-fishing-bridge | │ 86 │ def log_providers(self) -> None: │
camply-docker-compose-fishing-bridge | │ 87 │ │ """ │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/pushover.py:104 │
camply-docker-compose-fishing-bridge | │ in send_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 101 │ │ campsites: AvailableCampsite │
camply-docker-compose-fishing-bridge | │ 102 │ │ """ │
camply-docker-compose-fishing-bridge | │ 103 │ │ for campsite in campsites: │
camply-docker-compose-fishing-bridge | │ ❱ 104 │ │ │ message_title, formatted_dict = cls.format_standard_campsi │
camply-docker-compose-fishing-bridge | │ 105 │ │ │ │ campsite=campsite, │
camply-docker-compose-fishing-bridge | │ 106 │ │ │ ) │
camply-docker-compose-fishing-bridge | │ 107 │ │ │ fields = [] │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ /usr/local/lib/python3.9/site-packages/camply/notifications/base_notificatio │
camply-docker-compose-fishing-bridge | │ ns.py:79 in format_standard_campsites │
camply-docker-compose-fishing-bridge | │ │
camply-docker-compose-fishing-bridge | │ 76 │ │ │ │ key = "booking_link" │
camply-docker-compose-fishing-bridge | │ 77 │ │ │ elif key == CampsiteContainerFields.PERMITTED_EQUIPMENT: │
camply-docker-compose-fishing-bridge | │ 78 │ │ │ │ value = "\n - " + "\n - ".join( │
camply-docker-compose-fishing-bridge | │ ❱ 79 │ │ │ │ │ set(item.equipment_name for item in campsite.permit │
camply-docker-compose-fishing-bridge | │ 80 │ │ │ │ ) │
camply-docker-compose-fishing-bridge | │ 81 │ │ │ if key not in [CampsiteContainerFields.CAMPSITE_ATTRIBUTES] │
camply-docker-compose-fishing-bridge | │ 82 │ │ │ │ formatted_key = key.replace("
", " ").title() │
camply-docker-compose-fishing-bridge | ╰──────────────────────────────────────────────────────────────────────────────╯
camply-docker-compose-fishing-bridge | TypeError: 'NoneType' object is not iterable
camply-docker-compose-fishing-bridge exited with code 1
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,793 [ CAMPLY]: camply, the campsite finder ⛺️
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,796 [ INFO]: YAML File Parsed: search.yml
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,798 [ INFO]: 25 booking nights selected for search, ranging from 2023-06-05 to 2023-06-29
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,800 [ INFO]: Searching for availabilities with 3 consecutive night stays.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,801 [ INFO]: Searching for campsites every 5 minutes.
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,801 [ INFO]: Notifications active via: ,
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,801 [ INFO]: 1 Matching Campgrounds Found
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,802 [ INFO]: ⛰ Yellowstone National Park, USA (#1) - 🏕 Fishing Bridge RV Park (YLYF:RV)
camply-docker-compose-fishing-bridge | 2022-09-22 19:06:46,820 [ INFO]: Searching for Yellowstone Lodging Availability: June, 2023

Docker: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1131)

Thanks so much for sharing this software! Your documentation is awesome. Very excited to try this out. I hope this is not user error, but I'm getting the following error, in Docker with any query.

I haven't tried this yet with a local setup, just docker.

2021-08-29 12:15:21,496 [  CAMPLY]: Exiting camply 👋

Traceback (most recent call last):

  File "/usr/local/bin/camply", line 33, in <module>

    sys.exit(load_entry_point('camply==0.1.8', 'console_scripts', 'camply')())

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/utils/camply_cli.py", line 39, in main

    camply_cli.run_cli()

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/utils/camply_cli.py", line 418, in run_cli

    self.execute_cli_arguments()

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/utils/camply_cli.py", line 338, in execute_cli_arguments

    self.execute_campsites()

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/utils/camply_cli.py", line 405, in execute_campsites

    camping_finder.get_matching_campsites(**search_kwargs)

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/search/base_search.py", line 347, in get_matching_campsites

    self._search_campsites_continuous(log=log, verbose=verbose,

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/search/base_search.py", line 299, in _search_campsites_continuous

    self._continuous_search_retry(log=log, verbose=verbose,

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/search/base_search.py", line 228, in _continuous_search_retry

    notifier = CAMPSITE_NOTIFICATIONS.get(notification_provider.lower(),

  File "/usr/local/lib/python3.8/site-packages/camply-0.1.8-py3.8.egg/camply/notifications/email_notifications.py", line 56, in __init__

    _email_server = SMTP_SSL(EmailNotifications.email_smtp_server,

  File "/usr/local/lib/python3.8/smtplib.py", line 1043, in __init__

    SMTP.__init__(self, host, port, local_hostname, timeout,

  File "/usr/local/lib/python3.8/smtplib.py", line 255, in __init__

    (code, msg) = self.connect(host, port)

  File "/usr/local/lib/python3.8/smtplib.py", line 339, in connect

    self.sock = self._get_socket(host, port, self.timeout)

  File "/usr/local/lib/python3.8/smtplib.py", line 1051, in _get_socket

    new_socket = self.context.wrap_socket(new_socket,

  File "/usr/local/lib/python3.8/ssl.py", line 500, in wrap_socket

    return self.sslsocket_class._create(

  File "/usr/local/lib/python3.8/ssl.py", line 1040, in _create

    self.do_handshake()

  File "/usr/local/lib/python3.8/ssl.py", line 1309, in do_handshake

    self._sslobj.do_handshake()

ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1131)

GoingToCamp Parks Canada does not identify available sites correctly

Describe the bug

Going To Camp Parks Canada does not identify available sites correctly

Original Camply Command (with --debug)

camply --debug campsites   --provider goingtocamp   --rec-area 14   --campground -2147483648  --start-date 2023-09-01   --end-date 2023-09-02 --equipment-id -32768

Expected behavior
Sites are found and returned

Console Output (with --debug)

2023-08-10 00:26:29,171 [  CAMPLY]: camply, the campsite finder⛺️⛺
2023-08-10 00:26:29,172 [   DEBUG]: Setting up camply debugging
2023-08-10 00:26:29,172 [   DEBUG]: Camply Version: 0.29.0
2023-08-10 00:26:29,172 [   DEBUG]: Python Version: 3.9.17
2023-08-10 00:26:29,172 [   DEBUG]: Platform: linux
2023-08-10 00:26:29,174 [    INFO]: Using Camply Provider: "GoingToCamp"
2023-08-10 00:26:29,181 [    INFO]: 1 booking nights selected for search, ranging from 2023-09-01 to 2023-09-01
2023-08-10 00:26:29,184 [    INFO]: Retrieving Facility Information for Recreation Area ID: `14`.
2023-08-10 00:26:29,191 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:29,373 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/resourceLocation HTTP/1.1" 200 None
2023-08-10 00:26:29,442 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:29,761 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/maps HTTP/1.1" 200 None
2023-08-10 00:26:30,208 [    INFO]: 1 Matching Campgrounds Found
2023-08-10 00:26:30,209 [    INFO]: ⛰  Parks Canada (#14) - 🏕  Banff - Tunnel Mountain Village 2 (#-2147483648)
2023-08-10 00:26:30,228 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:30,418 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/availability/map?mapId=-2147483611&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768 HTTP/1.1" 200 None
2023-08-10 00:26:30,427 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:30,609 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/availability/map?mapId=-2147483610&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768 HTTP/1.1" 200 None
2023-08-10 00:26:30,630 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:30,750 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/availability/map?mapId=-2147483609&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768 HTTP/1.1" 200 None
2023-08-10 00:26:30,759 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:30,928 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/availability/map?mapId=-2147483608&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768 HTTP/1.1" 200 None
2023-08-10 00:26:30,938 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:31,049 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/availability/map?mapId=-2147483607&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768 HTTP/1.1" 200 None
2023-08-10 00:26:31,058 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:31,234 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/attribute/filterable HTTP/1.1" 200 None
2023-08-10 00:26:31,262 [   DEBUG]: Starting new HTTPS connection (1): reservation.pc.gc.ca:443
2023-08-10 00:26:31,382 [   DEBUG]: https://reservation.pc.gc.ca:443 "GET /api/resource/details?resourceId=-2147474297 HTTP/1.1" 200 None
2023-08-10 00:26:31,386 [    INFO]: ❌ ❌ ❌ ❌     0 Reservable Campsites Matching Search Preferences
2023-08-10 00:26:31,393 [  CAMPLY]: Exiting camply 👋


Additional context
Looking at the API return values: https://reservation.pc.gc.ca/api/availability/map?mapId=-2147483610&resourceLocationId=-2147483648&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&isReserving=True&getDailyAvailability=False&partySize=1&numEquipment=1&equipmentCategoryId=-32768&subEquipmentCategoryId=-32768

{"mapId":-2147483610,"mapAvailabilities":[5],"resourceAvailabilities":{"-2147474478":[{"availability":4,"remainingQuota":null}],"-2147474477":[{"availability":1,"remainingQuota":null}],"-2147474473":[{"availability":1,"remainingQuota":null}],"-2147474468":[{"availability":1,"remainingQuota":null}],"-2147474459":[{"availability":1,"remainingQuota":null}],"-2147474442":[{"availability":1,"remainingQuota":null}],"-2147474438":[{"availability":1,"remainingQuota":null}],"-2147474437":[{"availability":1,"remainingQuota":null}],"-2147474436":[{"availability":1,"remainingQuota":null}],"-2147474435":[{"availability":1,"remainingQuota":null}],"-2147474432":[{"availability":1,"remainingQuota":null}],"-2147474430":[{"availability":5,"remainingQuota":null}],"-2147474425":[{"availability":1,"remainingQuota":null}],"-2147474421":[{"availability":4,"remainingQuota":null}],"-2147474418":[{"availability":1,"remainingQuota":null}],"-2147474417":[{"availability":4,"remainingQuota":null}],"-2147474416":[{"availability":1,"remainingQuota":null}],"-2147474414":[{"availability":1,"remainingQuota":null}],"-2147474408":[{"availability":1,"remainingQuota":null}],"-2147474407":[{"availability":1,"remainingQuota":null}],"-2147474404":[{"availability":1,"remainingQuota":null}],"-2147474403":[{"availability":1,"remainingQuota":null}],"-2147474401":[{"availability":1,"remainingQuota":null}],"-2147474396":[{"availability":1,"remainingQuota":null}],"-2147474391":[{"availability":1,"remainingQuota":null}],"-2147474389":[{"availability":1,"remainingQuota":null}],"-2147474387":[{"availability":1,"remainingQuota":null}],"-2147474384":[{"availability":1,"remainingQuota":null}],"-2147474383":[{"availability":1,"remainingQuota":null}],"-2147474379":[{"availability":1,"remainingQuota":null}],"-2147474378":[{"availability":1,"remainingQuota":null}],"-2147474374":[{"availability":1,"remainingQuota":null}],"-2147474372":[{"availability":1,"remainingQuota":null}],"-2147474363":[{"availability":1,"remainingQuota":null}],"-2147474354":[{"availability":1,"remainingQuota":null}],"-2147474353":[{"availability":1,"remainingQuota":null}],"-2147474348":[{"availability":1,"remainingQuota":null}],"-2147474345":[{"availability":1,"remainingQuota":null}],"-2147474341":[{"availability":1,"remainingQuota":null}],"-2147474333":[{"availability":1,"remainingQuota":null}],"-2147474325":[{"availability":1,"remainingQuota":null}],"-2147474317":[{"availability":1,"remainingQuota":null}],"-2147474314":[{"availability":1,"remainingQuota":null}],"-2147474312":[{"availability":1,"remainingQuota":null}],"-2147474307":[{"availability":1,"remainingQuota":null}],"-2147474306":[{"availability":1,"remainingQuota":null}],"-2147474303":[{"availability":1,"remainingQuota":null}],"-2147474302":[{"availability":1,"remainingQuota":null}],"-2147474293":[{"availability":1,"remainingQuota":null}],"-2147474291":[{"availability":1,"remainingQuota":null}],"-2147474288":[{"availability":1,"remainingQuota":null}],"-2147474283":[{"availability":1,"remainingQuota":null}],"-2147474281":[{"availability":5,"remainingQuota":null}],"-2147474275":[{"availability":1,"remainingQuota":null}],"-2147474274":[{"availability":1,"remainingQuota":null}]},"mapLinkAvailabilities":{}}

The two sites marked "availability":5 are indeed available and lit up green in the web UI: https://reservation.pc.gc.ca/create-booking/results?mapId=-2147483610&searchTabGroupId=0&bookingCategoryId=0&startDate=2023-09-01&endDate=2023-09-02&nights=1&isReserving=true&equipmentId=-32768&subEquipmentId=-32761&partySize=1&filterData=%7B%22-32582%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%2C%22-32736%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%2C%22-32735%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%2C%22-32756%22%3A%22%5B%5B1%5D%2C0%2C1%2C0%5D%22%2C%22-32574%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%2C%22-32573%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%2C%22-32758%22%3A%22%5B%5B-1%5D%2C0%2C1%2C0%5D%22%7D&searchTime=2023-08-10T00%3A15%3A08.278&equipmentCapacity=1&resourceLocationId=-2147483648

Going to Camp self hosted sites

Is your feature request related to a problem? Please describe.
Add functionality for remaining Going to Camp / Camis provider self-hosted sites.
Michigan State Parks (MIDNRReservations.com) already added through this pull request: #176

Additional context
#94 (comment)
@acaloiaro

Filter campsites for goingtocamp

Is your feature request related to a problem? Please describe.
On top of the basic search parameters (campsite, date, equipment) goingtocamp uses filters to help users narrow down results to exactly what they're looking for. I would go so far as to say that they rely on these filters to allow campers to find the sites that they need. At the moment, camply doesn't seem to support passing filter values, which can result in lots of results returned that don't actually fit the camper's needs. The most useful I can think of is the site service type (Basic/None, Electric, Water, etc) and electrical service type (15amp, 30amp, 50amp).

The solution might be tricky, as it seems like the various goingtocamp rec areas are unique.

Describe the solution you'd like
To me, if we could query the rec area to get the list of filters, then use that as part of the campsite search, that would be the ideal solution.

camply filters --provider goingtocamp --rec-area 15
CAMPLY   camply, the campsite finder ⛺️
Using Camply Provider: "GoingToCamp"
Service Type (#-00001)
  No Preference
  Basic
  Electric
  Electric/Water
  Full
Electrical Service (#-00002)
  15 Amps
  20 Amps
  ...
Site Privacy (#-00003)
  No Preference
  Private
  ...
...

(example filters are from the Manitoba goingtocamp since I'm most familiar with those)

Then, when someone wants to search a campsite, they would pass the filter argument as a pair,

camply campsites --provider goingtocamp --rec-area 15 --campground -2147483635 --start-date 2023-08-25 --end-date 2023-08-27 --filter -00001 Electric

Describe alternatives you've considered

Additional context
Full disclosure, haven't investigated if it's even a possibility to ge the filter value's programatically. If not then this would be a bust since it would require camply to store too much hardcoded info for every provider that could change anytime. I will do some investigating.

Notifications over MQTT?

Is your feature request related to a problem? Please describe.
Greatly prefer local consumption of notifications.

Describe the solution you'd like
MQTT!

Describe alternatives you've considered

Additional context

list-campsites

Discussed in #238

Originally posted by steffanvigano April 5, 2023
Hi again,
It seems like Reserve California sites aren't searchable by specific campsite ID (number), is that correct? Couple questions (these also apply to the Yosemite Reservations):

  • Would it be possible to parse the campground for list of campsites using the API?

Sadly, the campsite ID is not part of the URL and looking at the page source, I don't seem to be able to find it. EX: New Brighton State Beach: https://www.reservecalifornia.com/Web/#!park/685/598 Our favorite sites are 73 and 75.

Something like:
camply campsites
--provider ReserveCalifornia
--campground 598
--list_campsites

  • If not, would it be possible to at least filter down to the results to Premium Sites only?

Not sure how they do it, by seems like WanderlingLabs has figured it out for this location.

Thanks again!
-S

Days of week & Test Notifications

Feature Request

  • Ability to test notifications
  • Search by any day of the week

Discussed in #226

Originally posted by steffanvigano March 24, 2023
Would love to see the following in the future:

Day Of Week Arrival:
-I see the weekends flag, but I work in the resort industry and weekends are for other people. Preferred would be day of week arrival. IE, I might want a site for 2 nights, between certain dates, and I can arrive either on a Tues or a Wed.

Test Notification Flag:
-With all campground selling out almost instantly, and all my trial runs coming back empty, it would be nice to be able to test out notifications rather than waiting for an eventual hit.

Date Windows:
-Rather than search across 4 months worth of dates, If I'm really only available to camp a couple specific weeks, it would be nice to only search those specific date ranges. IE. allow multiple, non overlapping, start and end dates. Currently in a YAML file, only the last defined dates are used. (I know I could just set up multiple YAML files and run different searches, so maybe this isn't needed)

Thanks!

yaml search with ReserveCalifornia fails with TypeError: object of type 'NoneType' has no len()

Describe the bug

When configuring camply to use a yaml file for searches, if the provider is ReserveCalifornia, it consistently exits with TypeError: object of type 'NoneType' has no len()

Original Camply Command (with --debug)

camply campsites --yaml-config my_search.yaml --debug

my_search.yaml content

provider: ReserveCalifornia
recreation_area: 1077
start_date: 2023-07-21
end_date: 2023-07-23

Expected behavior

Command should have the same output as when ReserveCalifornia is used with inline arguments.

Console Output (with --debug)

[2023-07-05 15:37:05] CAMPLY   camply, the campsite finder ⛺️                                                                                                                         
[2023-07-05 15:37:05] DEBUG    Setting up camply debugging                                                                                                                            
[2023-07-05 15:37:05] DEBUG    Camply Version: 0.27.0                                                                                                                                 
[2023-07-05 15:37:05] DEBUG    Python Version: 3.11.4                                                                                                                                 
[2023-07-05 15:37:05] DEBUG    Platform: darwin                                                                                                                                       
[2023-07-05 15:37:05] INFO     YAML File Parsed: my_search.yaml                                                                                                                       
[2023-07-05 15:37:05] INFO     Using Camply Provider: "ReserveCalifornia"                                                                                                             
[2023-07-05 15:37:05] INFO     2 booking nights selected for search, ranging from 2023-07-21 to 2023-07-22                                                                            
[2023-07-05 15:37:05] CAMPLY   Exiting camply 👋                                                                                                                                      
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/ixtli/.local/bin/camply:8 in <module>                                                     │
│                                                                                                  │
│   5 from camply.cli import cli                                                                   │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(cli())                                                                          │
│   9                                                                                              │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ cli = <function cli at 0x12ec04040>                                                          │ │
│ │  re = <module 're' from                                                                      │ │
│ │       '/opt/homebrew/Cellar/[email protected]/3.11.4_1/Frameworks/Python.framework/Versions/3.11/… │ │
│ │ sys = <module 'sys' (built-in)>                                                              │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/camply/cli.py:881 in cli      │
│                                                                                                  │
│   878 │   Camply Command Line Utility Wrapper                                                    │
│   879 │   """                                                                                    │
│   880 │   try:                                                                                   │
│ ❱ 881 │   │   camply_command_line()                                                              │
│   882 │   except KeyboardInterrupt:                                                              │
│   883 │   │   logger.debug("Handling Exit Request")                                              │
│   884 │   finally:                                                                               │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/core.py:1130 in         │
│ __call__                                                                                         │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/rich_click/rich_group.py:21   │
│ in main                                                                                          │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/core.py:1055 in main    │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/core.py:1657 in invoke  │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/core.py:1404 in invoke  │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/core.py:760 in invoke   │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/click/decorators.py:38 in     │
│ new_func                                                                                         │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/camply/cli.py:772 in          │
│ campsites                                                                                        │
│                                                                                                  │
│   769 │   │   │   yaml_config=yaml_config,                                                       │
│   770 │   │   )                                                                                  │
│   771 │   provider_class: Type[BaseCampingSearch] = CAMPSITE_SEARCH_PROVIDER[provider]           │
│ ❱ 772 │   camping_finder: BaseCampingSearch = provider_class(**provider_kwargs)                  │
│   773 │   camping_finder.get_matching_campsites(**search_kwargs)                                 │
│   774                                                                                            │
│   775                                                                                            │
│                                                                                                  │
│ ╭──────────────────────────────────────── locals ────────────────────────────────────────╮       │
│ │          campground = ()                                                               │       │
│ │            campsite = ()                                                               │       │
│ │             context = CamplyContext(debug=True, provider=None)                         │       │
│ │          continuous = False                                                            │       │
│ │                 day = ()                                                               │       │
│ │               debug = True                                                             │       │
│ │            end_date = ()                                                               │       │
│ │           equipment = ()                                                               │       │
│ │        equipment_id = None                                                             │       │
│ │              nights = 1                                                                │       │
│ │       notifications = ()                                                               │       │
│ │    notify_first_try = None                                                             │       │
│ │      offline_search = False                                                            │       │
│ │ offline_search_path = None                                                             │       │
│ │    polling_interval = None                                                             │       │
│ │            provider = 'ReserveCalifornia'                                              │       │
│ │      provider_class = <class 'camply.search.search_usedirect.SearchReserveCalifornia'> │       │
│ │     provider_kwargs = {                                                                │       │
│ │                       │   'search_window': SearchWindow(                               │       │
│ │                       │   │   start_date=datetime.date(2023, 7, 21),                   │       │
│ │                       │   │   end_date=datetime.date(2023, 7, 23)                      │       │
│ │                       │   ),                                                           │       │
│ │                       │   'recreation_area': 1077,                                     │       │
│ │                       │   'campgrounds': None,                                         │       │
│ │                       │   'campsites': None,                                           │       │
│ │                       │   'weekends_only': False,                                      │       │
│ │                       │   'days_of_the_week': None,                                    │       │
│ │                       │   'nights': 1,                                                 │       │
│ │                       │   'equipment': None,                                           │       │
│ │                       │   'offline_search': False,                                     │       │
│ │                       │   'offline_search_path': None                                  │       │
│ │                       }                                                                │       │
│ │            rec_area = ()                                                               │       │
│ │      search_forever = None                                                             │       │
│ │       search_kwargs = {                                                                │       │
│ │                       │   'log': True,                                                 │       │
│ │                       │   'verbose': True,                                             │       │
│ │                       │   'continuous': True,                                          │       │
│ │                       │   'polling_interval': 10,                                      │       │
│ │                       │   'notify_first_try': False,                                   │       │
│ │                       │   'notification_provider': 'silent',                           │       │
│ │                       │   'search_forever': False,                                     │       │
│ │                       │   'search_once': False                                         │       │
│ │                       }                                                                │       │
│ │         search_once = False                                                            │       │
│ │          start_date = ()                                                               │       │
│ │            weekends = False                                                            │       │
│ │         yaml_config = '/Users/ixtli/my_search.yaml'                                    │       │
│ ╰────────────────────────────────────────────────────────────────────────────────────────╯       │
│                                                                                                  │
│ /Users/ixtli/.local/pipx/venvs/camply/lib/python3.11/site-packages/camply/search/search_usedirec │
│ t.py:84 in __init__                                                                              │
│                                                                                                  │
│    81 │   │   self._recreation_area_ids: List[int] = make_list(recreation_area, coerce=int)      │
│    82 │   │   self._campground_ids: List[int] = make_list(campgrounds, coerce=int)               │
│    83 │   │   campsites = make_list(kwargs.get("campsites", []), coerce=int)                     │
│ ❱  84 │   │   if len(campsites) > 0:                                                             │
│    85 │   │   │   self.campsite_finder.validate_campsites(                                       │
│    86 │   │   │   │   campsites=campsites, facility_ids=self._campground_ids                     │
│    87 │   │   │   )                                                                              │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │     campgrounds = None                                                                       │ │
│ │       campsites = None                                                                       │ │
│ │          kwargs = {                                                                          │ │
│ │                   │   'campsites': None,                                                     │ │
│ │                   │   'days_of_the_week': None,                                              │ │
│ │                   │   'equipment': None,                                                     │ │
│ │                   │   'offline_search': False,                                               │ │
│ │                   │   'offline_search_path': None                                            │ │
│ │                   }                                                                          │ │
│ │          nights = 1                                                                          │ │
│ │ recreation_area = 1077                                                                       │ │
│ │   search_window = SearchWindow(                                                              │ │
│ │                   │   start_date=datetime.date(2023, 7, 21),                                 │ │
│ │                   │   end_date=datetime.date(2023, 7, 23)                                    │ │
│ │                   )                                                                          │ │
│ │            self = <camply.search.search_usedirect.SearchReserveCalifornia object at          │ │
│ │                   0x10eb89810>                                                               │ │
│ │   weekends_only = False                                                                      │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: object of type 'NoneType' has no len()


Additional context

Formatting the above search as an inline command successfully completes:

camply --debug campsites \
    --provider ReserveCalifornia \
	--rec-area 1077 \
	--start-date 2023-07-21 \
	--end-date 2023-07-23

Broken URL in notifications

When an alert fires for a Yellowstone site, Fishing Bridge in this case, the url included in the notification does not take you to the correct page.

This is the url that is generated:

https://secure.yellowstonenationalparklodges.com/booking/lodging-select/YLYF:RV?dateFrom=06-15-2022&nights=3

This url takes you to the general entrance page for booking a reservation. The date range is not entered on the page and the specific campground is not selected.

It looks like the site has changed their url structure.

Specific campgrounds not returned using GoingToCamp provider on windows

Describe the bug

when I use

camply campgrounds --provider goingtocamp --rec-area 3

lots of campgrounds are listed

...
[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Twenty-Five Mile Creek State Park

                               (#-2147483548)
[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Twin Harbors State Park  (#-2147483547)

[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Wallace Falls State Park  (#-2147483545)

[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Wanapum State Park  (#-2147483544)

[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Wenatchee Confluence State Park

                               (#-2147483543)
[2023-06-05 07:50:53] INFO     ⛰  Washington State Parks, Washington (#3) - 🏕  Yakima Sportsman State Park

                               (#-2147483540)

When i try to search a specific one of these campgrounds I get this message:

camply campgrounds --provider goingtocamp --rec-area 3 --campground -2147483572
[2023-06-05 07:53:33] INFO     Using Camply Provider: "GoingToCamp"
[2023-06-05 07:53:33] INFO     Retrieving Facility Information for Recreation Area ID: `3`.
[2023-06-05 07:53:33] INFO     0 Matching Campgrounds Found
[2023-06-05 07:53:33] CAMPLY   Exiting camply 👋

Original Camply Command (with --debug)

camply campgrounds --provider goingtocamp --rec-area 3 --campground -2147483572

Expected behavior
I expect information about the campground to be returned

Console Output (with --debug)

[2023-06-05 08:00:13] CAMPLY   camply, the campsite finder ⛺️

[2023-06-05 08:00:13] INFO     Using Camply Provider: "GoingToCamp"
[2023-06-05 08:00:13] DEBUG    Setting up camply debugging
[2023-06-05 08:00:13] DEBUG    Camply Version: 0.23.0
[2023-06-05 08:00:13] DEBUG    Python Version: 3.10.5
[2023-06-05 08:00:13] DEBUG    Platform: win32
[2023-06-05 08:00:13] INFO     Retrieving Facility Information for Recreation Area ID: `3`.
[2023-06-05 08:00:13] DEBUG    Starting new HTTPS connection (1): washington.goingtocamp.com:443
[2023-06-05 08:00:14] DEBUG    https://washington.goingtocamp.com:443 "GET /api/resourceLocation HTTP/1.1" 200 None
[2023-06-05 08:00:14] DEBUG    Starting new HTTPS connection (1): washington.goingtocamp.com:443
[2023-06-05 08:00:14] DEBUG    https://washington.goingtocamp.com:443 "GET /api/maps HTTP/1.1" 200 None
[2023-06-05 08:00:14] INFO     0 Matching Campgrounds Found
[2023-06-05 08:00:14] CAMPLY   Exiting camply 👋

Additional context

When I use a similar command for recreation.gov, things work as expected:

camply campgrounds --campground 259084
[2023-06-05 08:03:31] CAMPLY   camply, the campsite finder ⛺️

[2023-06-05 08:03:31] INFO     Using Camply Provider: "RecreationDotGov"
[2023-06-05 08:03:33] INFO     1 Matching Campgrounds Found
[2023-06-05 08:03:33] INFO     ⛰  Olympic National Park, USA (#2881) - 🏕  Fairholme Campground  (#259084)

[2023-06-05 08:03:33] CAMPLY   Exiting camply 👋

Implement More State Parks

Is your feature request related to a problem? Please describe.

After #208 gets across the line - it provides a clear path to easily implement all instances of States/Systems using UseDirect.

After a quick Google Search I can already find a lot of other states using this like Ohio and Minnesota.

Describe the solution you'd like

Simple Implementations for UseDirect Providers

Feature Request - Days of week & Test Notifications

Discussed in #226

Originally posted by steffanvigano March 24, 2023
Would love to see the following in the future:

Day Of Week Arrival:
-I see the weekends flag, but I work in the resort industry and weekends are for other people. Preferred would be day of week arrival. IE, I might want a site for 2 nights, between certain dates, and I can arrive either on a Tues or a Wed.

Test Notification Flag:
-With all campground selling out almost instantly, and all my trial runs coming back empty, it would be nice to be able to test out notifications rather than waiting for an eventual hit.

Date Windows:
-Rather than search across 4 months worth of dates, If I'm really only available to camp a couple specific weeks, it would be nice to only search those specific date ranges. IE. allow multiple, non overlapping, start and end dates. Currently in a YAML file, only the last defined dates are used. (I know I could just set up multiple YAML files and run different searches, so maybe this isn't needed)

Thanks!

This isse partially addresses the above discussion by enabling the ability to provide multiple search windows.

Trouble using search yaml file with equipment option

Describe the bug

Searching for campsites using a yaml file config is not working as I would expected. The equipment type does not seem to be recognized. I am seeing these warnings in the log. This could be user error, but I put as much detail as I could figure out.

[2023-07-20 22:41:06] WARNING  Equipment name not recognized: R. This won't be used for filtering. Acceptable options
                               are: tent, rv, trailer, vehicle
[2023-07-20 22:41:06] WARNING  Equipment name not recognized: 2. This won't be used for filtering. Acceptable options
                               are: tent, rv, trailer, vehicle

I put a breakpoint at line 158 in search_recreationdotgov.py and saw that the equipment tuple was over expanded

 if isinstance(equipment, (list, tuple)):
157                 final_equipment = []
158                 breakpoint()
159  ->             for equipment_name, equipment_length in equipment:
160                     if (
(Pdb) equipment
[('R', 'V'), ('2', '5')]

Also the length of 25 is being treated as a string (and split).

Original Camply Command (with --debug)

pipenv run camply campsites --yaml-config proof.yaml --debug > debug.txt

Expected behavior
I expected the equipment type to be parsed into an equipment type string and length integer.

Console Output (with --debug)

debug.txt

Additional context

< Add any other context about the problem here. >

This is my yaml file, it is similar to the sample from the docs.

   - 2991
start_date: 2023-07-29
end_date: 2023-08-02
nights: 1
equipment: [RV, 25]

I tired to do as suggested in the docs of

...
equipment: 
  - [RV, 25]. # Make this an array.

But i get this error

ValidationError: 4 validation errors for YamlSearchFile
equipment
  value is not a valid integer (type=type_error.integer)
equipment -> 0
  value is not a valid integer (type=type_error.integer)
equipment
  str type expected (type=type_error.str)
equipment -> 0
  str type expected (type=type_error.str)

I am not sure if this is 1 or 2 issues.

Thanks in advance!

Documentation on How To Implement a New Provider

Is your feature request related to a problem? Please describe.

Camply aims to support new local, state, federal, and international camping providers. Currently, there isn't any centralized documentation on this process or an extremely clean provider to be used as an example. Now that ReserveCalifornia has been implemented we have a somewhat simple provider implementation contained within a PR - this is a great example for future providers.

Describe the solution you'd like

Create a clean documentation guide on how to create a new provider. This guide needs to cover the following details:

  • Implementing an ABC Provider Class
  • Implementing the corresponding ABC Search Class
  • Integrating the new provider/search into the CLI
  • Documenting usage of the new provider
  • Link to the aforementioned PR to demonstrate

Breakage when `rich` version < `10.0.0`

Describe the bug
Camply uses a rich.logging.RichHandler named parameter that was only made available in rich 10.0.0 (Textualize/rich@c235db4)

To Reproduce
Steps to reproduce the behavior:

  1. Run camply on any system with a version of rich < 10.0.0 previously installed
  2. TypeError: RichHandler.__init__() got an unexpected keyword argument 'omit_repeated_times'

Expected behavior
The CLI runs

Screenshots

Traceback (most recent call last):
  File "/home/adriano/.asdf/installs/python/3.10.1/bin//camply", line 33, in <module>
    sys.exit(load_entry_point('camply==0.4.3', 'console_scripts', 'camply')())
  File "/home/adriano/.asdf/installs/python/3.10.1/bin//camply", line 25, in importlib_load_entry_point
    return next(matches).load()
  File "/home/adriano/.asdf/installs/python/3.10.1/lib/python3.10/importlib/metadata/__init__.py", line 162, in load
    module = import_module(match.group('module'))
  File "/home/adriano/.asdf/installs/python/3.10.1/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/adriano/.asdf/installs/python/3.10.1/lib/python3.10/site-packages/camply/cli.py", line 14, in <module>
    from camply.config.logging_config import set_up_logging
  File "/home/adriano/.asdf/installs/python/3.10.1/lib/python3.10/site-packages/camply/config/logging_config.py", line 13, in <module>
    rich_handler = RichHandler(
TypeError: RichHandler.__init__() got an unexpected keyword argument 'omit_repeated_times'

Environment (please complete the following information):

  • OS: [e.g. Windows, Mac, Linux, Docker]
  • Python Version [e.g. 3.6, 3.9]
  • Camply Version [e.g. 0.1.1]

Additional context
Add any other context about the problem here.

Ability to specify # of people for a campsite

Is your feature request related to a problem? Please describe.
I have a trip I'm looking for a campsite for where we have 10 people. This is more than many sites 6 & 8 person maximum. We have double occupancy sites here in WA that allow up to 12 people. It would be nice to be able to specify our desired occupancy when running camply.
Describe the solution you'd like
Similar to equipment, it would be great to be able specify occupancy
For the CLI, like this:

... --occupancy 10

For yaml config, like this:

...
occupancy: 10

Describe alternatives you've considered
Beyond looking for a single campsite at the specified occupancy it would be cool to be able to specify either more than one campsite or that the occupancy could be split across multiple campsites.

February 2022: No Pushover Credits Available

Describe the bug
I'm so sorry everyone. There was a unforseen event that caused 10,000 messages via Pushover and used up all Pushover Credits. The issue has been resolved and a new Pushover App has been created. If you're using an older version of Camply in February 2022 then Pushover notifications won't work.

Additional context
To resolve this problem you can just upgrade camply: pip install --upgrade camply

Olympic National Park doesn't appear as a WA Recreation area

Describe the bug

The output of camply recreation-areas --state WA does not include ⛰ Olympic National Park, WA (#2881).

When I run camply campgrounds --rec-area 2881
I get this output:

[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, USA (#2881) - 🏕  Fairholme Campground   (#259084)            
[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, USA (#2881) - 🏕  Staircase Campground   (#247586)            
[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, WA (#2881) - 🏕  Hoh Rainforest Campground   (#247592)        
[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, WA (#2881) - 🏕  Kalaloch   (#232464)                         
[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, WA (#2881) - 🏕  Mora Campground   (#247591)                  
[2023-06-17 09:14:46] INFO     ⛰  Olympic National Park, WA (#2881) - 🏕  Sol Duc Hot Springs Resort Campground  (#251906)

I wonder if this has something to do with the fact that some of the campgrounds report as USA despite being in Washington.

Original Camply Command (with --debug)

[2023-06-17 09:18:09] INFO     Using Camply Provider: "RecreationDotGov"
[2023-06-17 09:18:09] DEBUG    Setting up camply debugging
[2023-06-17 09:18:09] DEBUG    Camply Version: 0.24.3
[2023-06-17 09:18:09] DEBUG    Python Version: 3.10.5
[2023-06-17 09:18:09] DEBUG    Platform: win32
[2023-06-17 09:18:09] INFO     Retrieving Facility Information for Recreation Area ID: `2881`.
[2023-06-17 09:18:09] DEBUG    Starting new HTTPS connection (1): ridb.recreation.gov:443
[2023-06-17 09:18:10] DEBUG    https://ridb.recreation.gov:443 "GET
                               /api/v1/recareas/2881/facilities?full=true&offset=0 HTTP/1.1" 200 130200
...

I receive "Availability Status: Closed" alerts, how to filter them?

I receive "Availability Status: Closed" notifications for the following cmd:

camply campsites --rec-area 2931 --start-date 2023-06-09 --end-date 2023-06-13 --notifications pushbullet --search-forever --equipment RV 0 --campground 232461

I can see the code checks the status against CAMPSITE_UNAVAILABLE_STRINGS constant list, "Closed" is in this list, but I still get the alerts where Status is "Closed", how to filter them further to make sure I receive alerts only for "Available" sites?

cannot search on ReserveCalifornia

Describe the bug

I upgraded to 0.24.2 today, but I found out I cannot run the same command to search on Reserve California anymore. Don't know if it's related to my raspberryPi because I tried the same commands on another x86 Ubuntu with Camply 0.24.2, everything worked.

I tried remove camply 0.24.2 and its dependencies and re-installed camply again, problem is still there. Also tried install older version, same issue.

Original Camply Command (with --debug)

pi@raspberrypi:~ $ camply --debug campsites --provider ReserveCalifornia --campground 406 --campground 408 --campground 409 --start-date 2023-06-09 --end-date 2023-07-01 --day Saturday --notifications pushover --polling-interval 5 --search-forever

Expected behavior
expect to search the campsites on ReserveCalifornia, the command worked before upgrade.

Console Output (with --debug)

[2023-06-06 15:38:38] CAMPLY camply, the campsite finder ⛺️
[2023-06-06 15:38:38] DEBUG Setting up camply debugging
[2023-06-06 15:38:38] DEBUG Camply Version: 0.24.2
[2023-06-06 15:38:38] DEBUG Python Version: 3.9.2
[2023-06-06 15:38:38] DEBUG Platform: linux
[2023-06-06 15:38:38] INFO Using Camply Provider: "ReserveCalifornia"
[2023-06-06 15:38:38] INFO 3 booking nights selected for search, ranging from 2023-06-10 to 2023-06-24
[2023-06-06 15:38:38] INFO Searching for booking nights on Saturday
[2023-06-06 15:38:39] ERROR No Campsites Found Matching Your Search Criteria
[2023-06-06 15:38:39] CAMPLY Exiting camply 👋

Additional context

Don't know if it's related to my raspberryPi because I tried the same commands on another x86 Ubuntu with Camply 0.24.2, everything worked.

Hide Not Yet Released Sites

Is your feature request related to a problem? Please describe.
When running a search for 4th of July week at Yellowstone, Camply is returning many sites open, but none of them are reservable until two weeks out.

Visitors can make a reservation six weeks in advance for 80% of the camping spots at Indian Creek, Lewis Lake, Pebble Creek, Mammoth and Slough Creek, reservations for the other 20% will open two weeks in advance.

Describe the solution you'd like
Is it possible to filter out Not Yet Released (NR) reservations?

Describe alternatives you've considered

Additional context

2022-05-18 20:16:55,479 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068683 (5 nights) 2022-05-18 20:16:55,479 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068684 (5 nights) 2022-05-18 20:16:55,479 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068685 (5 nights) 2022-05-18 20:16:55,479 [ INFO]: ⛰️ Yellowstone National Park, WY 🏕 Lewis Lake Campground: ⛺ 17 sites 2022-05-18 20:16:55,482 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077164 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077166 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077167 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077169 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077175 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077179 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077180 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077181 (5 nights) 2022-05-18 20:16:55,483 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077185 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077186 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077188 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077189 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077190 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077191 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077192 (5 nights) 2022-05-18 20:16:55,484 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077206 (5 nights) 2022-05-18 20:16:55,485 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077215 (5 nights) 2022-05-18 20:16:55,485 [ INFO]: 📅 Tue, July 05 🏕 36 sites 2022-05-18 20:16:55,490 [ INFO]: ⛰️ Yellowstone National Park, USA 🏕 Pebble Creek Campground: ⛺ 5 sites 2022-05-18 20:16:55,494 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068704 (5 nights) 2022-05-18 20:16:55,494 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068705 (5 nights) 2022-05-18 20:16:55,494 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068706 (5 nights) 2022-05-18 20:16:55,494 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068707 (5 nights) 2022-05-18 20:16:55,494 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068713 (5 nights) 2022-05-18 20:16:55,495 [ INFO]: ⛰️ Yellowstone National Park, WY 🏕 Indian Creek Campground (Yellowstone): ⛺ 14 sites 2022-05-18 20:16:55,498 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068620 (5 nights) 2022-05-18 20:16:55,498 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068623 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068625 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068632 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068645 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068647 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068662 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068663 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068671 (5 nights) 2022-05-18 20:16:55,499 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068681 (5 nights) 2022-05-18 20:16:55,500 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068682 (5 nights) 2022-05-18 20:16:55,500 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068683 (5 nights) 2022-05-18 20:16:55,500 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068684 (5 nights) 2022-05-18 20:16:55,500 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10068685 (5 nights) 2022-05-18 20:16:55,500 [ INFO]: ⛰️ Yellowstone National Park, WY 🏕 Lewis Lake Campground: ⛺ 17 sites 2022-05-18 20:16:55,503 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077164 (5 nights) 2022-05-18 20:16:55,504 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077166 (5 nights) 2022-05-18 20:16:55,504 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077167 (5 nights) 2022-05-18 20:16:55,504 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077169 (5 nights) 2022-05-18 20:16:55,504 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077175 (5 nights) 2022-05-18 20:16:55,504 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077179 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077180 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077181 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077185 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077186 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077188 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077189 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077190 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077191 (5 nights) 2022-05-18 20:16:55,505 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077192 (5 nights) 2022-05-18 20:16:55,506 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077206 (5 nights) 2022-05-18 20:16:55,506 [ INFO]: 🔗 https://www.recreation.gov/camping/campsites/10077215 (5 nights) 2022-05-18 20:16:55,506 [ INFO]: 180 New Campsites Found. 2022-05-18 20:16:55,507 [ WARNING]: Too many campsites were found during the search (180 total). camply will only send you the first 20 notifications.

Add campsite type include/exclude option for provider ReserveCalifornia

Is your feature request related to a problem? Please describe.
When I searched campsite in Henry Cowell Redwoods SP, it always showed availability. However, when I checked the link as below, I found it was due to one site (Walk-In Only) was always available.
https://www.reservecalifornia.com/Web/Default.aspx#!park/655/505

Describe the solution you'd like
I would like an argument that can specify what kind of campsite to include or exclude. That would be neat.

Describe alternatives you've considered
For this use case, I don't have a workaround.

Additional context

Pinnacles Campground not supported

Hi,

I was trying to run camply against pinnacles campground. For some reason I could not get this to work.
I have used the campground ID "234015" from recreation.gov camply could not find it.

camply campsites --rec-area 234015 --start-date 2023-07-10 --end-date 2023-07-18 --notifications silent --search-forever

Is my approach wrong?
Thank you!

Date Reset Bugs

Describe the bug

I suspect weird stuff is happening when months switch over while you're inside a search window.

Here's the scenario:

  1. You start a camply search on 1/30/2023 for a flexible time period covering the next week:

    camply --debug campsites \
      --campground 12345 \
      --start-date 2023-01-30 \
      --end-date 2023-02-07 \
      --continuous \
      --search-forever \
      --notifications pushover
  2. When the month changes over from January to February, spooky stuff happens. This part I'm not 100% on but I've suspected it for a while. There are some attributes like search_days and search_months that are static instead of dynamic.

I believe we would be better off if search_days and search_months are dynamic based on the datetime at atribute fetch time (@property)

Support for reservations.ontarioparks.com (goingtocamp)

Is your feature request related to a problem? Please describe.
The Ontario parks booking system seems to run on goingtocamp in spite of the custom domain name (I was able to make a basic api requests with goingtocamp endpoints). AFAIK it seems like it should be able to be added as a goingtocamp rec area.

Describe the solution you'd like
reservations.ontarioparks.com added as a goingtocamp rec area

Additional context
Seeing the previous PRs, I may try to implement this myself (though don't wait if you've got it 😅).

Send notification to user if camply encounters error

Hi Camply developer,

Great software! helped me to book Yosemite NP camping for memorial long weekend! Kudos!

Today I encountered an error that camply exited itself during search for ReserveCalifornia after approximately 48 hours. Below is the log.


ReserveCaliforniaError: Error Parsing ReserveCalifornia Availability Response - Facility ID # 408. Invalid FacilityId specified for facility grid
search on CALIRDR5

I wonder if we can have a last word style of notification before camply exits itself? so user could re-run it after receiving the notification. Thanks a million!

Filtering Campsites

I’m looking to a filter the alerts I get to ones that meet my requirements (e.g. trailer size).

How would you recommend I implement this?

Notifications for closed campsites

Hi 👋

First of all, thanks for maintaining this project. I just started using it recently and I’m very excited at the idea of potentially finding a campsite!

I just ran into a problem today: I’m getting notified for campsites, but the notification says « Availability status: closed » and on recreation.gov, the campsites show as « unavailable ».

Here’s the command I’m using:

camply campsites \
    --campground 232450 \
    --campground 232449 \
    --campground 232447 \
    --start-date 2023-07-21 \
    --end-date 2023-08-13 \
    --notifications slack \
    --search-forever

And an example campsite that is being returned: https://www.recreation.gov/camping/campsites/947

6D3B31BE-BC81-4A76-B08B-0344DE932567

Support for manitoba.goingtocamp.com

Is your feature request related to a problem? Please describe.
Manitoba parks booking service has migrated to goingtocamp and would be great to add into a future release

Describe the solution you'd like
manitoba.goingtocamp.com supported by camply

Describe alternatives you've considered

Additional context
Very cool having a tool like this, great work!

Going To Camp support

Is your feature request related to a problem? Please describe.
This is a tracking issue for adding Going To Camp support.

A Going to Camp provider will add support for the following areas

  • Washing State Parks

  • Wisconsin State Parks

  • City of Oroville (WA)

  • Tacoma Power Parks (WA)

  • Longpoint Area (CA)

  • Saugeen Valley Conservation Area (Canada)

  • St. Clair Conservation Authority (Canada)

  • Yukon Parks (Canada)

Other Going to Camp providers may be possible, but it looks like they use some sort of self-hosted solution that makes the API more difficult to work with (and sometimes blocked because javascript is not active, or an unacceptable browser UA is in use).


I plan to implement an initial proof of concept shortly.

Describe the solution you'd like

Describe alternatives you've considered

Additional context

API calls blocked

As of yesterday, my Camply API calls to recreation.gov are blocked.

Here's the error I am getting back from Camply:

Error: 403
Request blocked.

<TITLE>ERROR: The request could not be satisfied</TITLE>

403 ERROR

The request could not be satisfied.


Request blocked. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.

Generated by cloudfront (CloudFront)
Request ID: -duVM4wmJCI8E0sAi7ZfMguXA7_p3nVi6JRuT64Cuxp7FfeYd-lg1Q==

I've tried changing ip addresses with no luck.
I've tried changing to my own API key with no luck.

Any suggestions?

Is there a way to specify a different User-Agent header?

Thanks!!

Rick

Help text typo for start_date

The following help text has a typo: start_date vs start-date

[2022-07-11 15:43:50] ERROR    Campsite searches require the following mandatory search parameters: --start_date,
                               --end-date

Support "Timed Entry" tickets

Is your feature request related to a problem? Please describe.
AFAICT, the "Timed Entry" type of tickets/passes (such as https://www.recreation.gov/timed-entry/10088426) do not show up for a rec-area.

Describe the solution you'd like
Include "Timed Entry" types of tickets/passes

Describe alternatives you've considered
None

Additional context
Add any other context or screenshots about the feature request here.
Arches National Park Timed Entry (https://www.recreation.gov/timed-entry/10088426) has availability in April, but camply only shows Campground sites:

$ camply campsites --rec-area 2573 --start-date 2022-02-03 --end-date 2022-05-04
2022-02-28 20:01:35,927 [  CAMPLY]: camply, the campsite finder ⛺️
2022-02-28 20:01:35,960 [    INFO]: 65 booking nights selected for search, ranging from 2022-02-28 to 2022-05-03
2022-02-28 20:01:35,967 [    INFO]: 4 different months selected for search, ranging from 2022-02-28 to 2022-05-03
2022-02-28 20:01:35,973 [    INFO]: Retrieving Facility Information for Recreation Area ID: `2573`.
2022-02-28 20:01:38,026 [    INFO]: 1 Matching Campgrounds Found
2022-02-28 20:01:38,027 [    INFO]: ⛰  Arches National Park, UT (#2573) - 🏕  Devils Garden Campground (#234059)
2022-02-28 20:01:38,028 [    INFO]: Searching across 1 campgrounds
2022-02-28 20:01:38,028 [    INFO]: Searching Devils Garden Campground, Arches National Park, UT (234059) for availability: February, 2022
2022-02-28 20:01:38,192 [    INFO]:     ❌      0 total sites found in month of February
2022-02-28 20:01:38,193 [    INFO]: Searching Devils Garden Campground, Arches National Park, UT (234059) for availability: March, 2022
2022-02-28 20:01:38,392 [    INFO]:     ⛺️      2 total sites found in month of March
2022-02-28 20:01:38,393 [    INFO]: Searching Devils Garden Campground, Arches National Park, UT (234059) for availability: April, 2022
2022-02-28 20:01:38,668 [    INFO]:     ❌      0 total sites found in month of April
2022-02-28 20:01:38,669 [    INFO]: Searching Devils Garden Campground, Arches National Park, UT (234059) for availability: May, 2022
2022-02-28 20:01:38,906 [    INFO]:     ❌      0 total sites found in month of May
2022-02-28 20:01:38,952 [    INFO]: ⛺️ ⛺️ ⛺️ ⛺️ 2 Reservable Campsites Matching Search Preferences
2022-02-28 20:01:38,955 [    INFO]: 📅 Thu, March 10 🏕  2 sites
2022-02-28 20:01:38,956 [    INFO]:     ⛰️  Arches National Park, UT  🏕  Devils Garden Campground: ⛺ 2 sites
2022-02-28 20:01:38,959 [    INFO]:             🔗 https://www.recreation.gov/camping/campsites/7451 (1 night)
2022-02-28 20:01:38,960 [    INFO]:             🔗 https://www.recreation.gov/camping/campsites/7871 (1 night)
2022-02-28 20:01:38,961 [  CAMPLY]: Exiting camply 👋

Add feature to ignore errors instead of stopping the tracking

Describe the bug

When a provider (ReserveCalifornia in my case) encounters an error the script just exists and stop tracking. The errors are happening very often for ReserveCalifornia so the script become very unreliable.

So I switched to cron. Yet with every time the script encounter an error it sends a notification (which makes script not very useful). Tracking just one date for one campsite I encountered 18 errors over 12 hours run (every 10 minutes). I got 18 notifications over 12 hours which made the notifications more like a spam rather than a useful info.

Original Camply Command (with --debug)

docker run -it \
-e TELEGRAM_BOT_TOKEN=[...] -e TELEGRAM_CHAT_ID=[...] \
juftin/camply camply --provider ReserveCalifornia campsites \
--rec-area 726 --start-date 2023-06-10 --end-date 2023-06-11 \
--notifications telegram \
--search-once 

Expected behavior
Add 2 options:

  1. fail the script after N errors
  2. skip the notification on error

Console Output (with --debug)

2023-06-06 05:18:27,786 [    INFO]: Searching across 1 campgrounds
2023-06-06 05:18:27,786 [    INFO]:     ⛰  Sunset SB (#726) - 🏕  South Camp (sites 1-37) (#737)
2023-06-06 05:18:27,786 [    INFO]: Searching South Camp (sites 1-37), Sunset SB (737) for availability: June, 2023
2023-06-06 05:18:27,910 [    INFO]: Exception encountered, emitting notification last gasp.
2023-06-06 05:18:28,494 [  CAMPLY]: Exiting camply 👋
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:328 in            │
│ get_campsites_response                                                                           │
│                                                                                                  │
│   325 │   │   response.raise_for_status()                                                        │
│   326 │   │   response_json = response.json()                                                    │
│   327 │   │   try:                                                                               │
│ ❱ 328 │   │   │   return UseDirectAvailabilityResponse(**response.json())                        │
│   329 │   │   except ValidationError as e:                                                       │
│   330 │   │   │   error_message = (                                                              │
│   331 │   │   │   │   "Error Parsing UseDirect Availability Response "                           │
│                                                                                                  │
│ in pydantic.main.BaseModel.__init__:341                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ValidationError: 10 validation errors for UseDirectAvailabilityResponse
Filters
  none is not an allowed value (type=type_error.none.not_allowed)
EndDate
  none is not an allowed value (type=type_error.none.not_allowed)
TimeZone
  none is not an allowed value (type=type_error.none.not_allowed)
TimeStamp
  none is not an allowed value (type=type_error.none.not_allowed)
UnitSort
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Name
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Description
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Restrictions
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> SeasonDates
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> TrafficStatuses
  none is not an allowed value (type=type_error.none.not_allowed)

The above exception was the direct cause of the following exception:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:574 in                       │
│ get_matching_campsites                                                                           │
│                                                                                                  │
│    571 │   │   """                                                                               │
│    572 │   │   if continuous is True or search_once is True:                                     │
│    573 │   │   │   try:                                                                          │
│ ❱  574 │   │   │   │   self._search_campsites_continuous(                                        │
│    575 │   │   │   │   │   log=log,                                                              │
│    576 │   │   │   │   │   verbose=verbose,                                                      │
│    577 │   │   │   │   │   polling_interval=polling_interval,                                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:508 in                       │
│ _search_campsites_continuous                                                                     │
│                                                                                                  │
│    505 │   │   continuous_search_attempts = 1                                                    │
│    506 │   │   while continuous_search is True:                                                  │
│    507 │   │   │   starting_count = len(self.campsites_found)                                    │
│ ❱  508 │   │   │   self._continuous_search_retry(                                                │
│    509 │   │   │   │   log=log,                                                                  │
│    510 │   │   │   │   verbose=verbose,                                                          │
│    511 │   │   │   │   polling_interval=polling_interval,                                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:354 in                       │
│ _continuous_search_retry                                                                         │
│                                                                                                  │
│    351 │   │   │   retry=tenacity.retry_if_exception_type(CampsiteNotFoundError),                │
│    352 │   │   │   wait=tenacity.wait.wait_fixed(int(polling_interval_minutes) * 60),            │
│    353 │   │   )                                                                                 │
│ ❱  354 │   │   matching_campsites = retryer.__call__(                                            │
│    355 │   │   │   fn=self._search_matching_campsites_available,                                 │
│    356 │   │   │   log=False,                                                                    │
│    357 │   │   │   verbose=False,                                                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:379 in __call__                      │
│                                                                                                  │
│   376 │   │                                                                                      │
│   377 │   │   retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs)   │
│   378 │   │   while True:                                                                        │
│ ❱ 379 │   │   │   do = self.iter(retry_state=retry_state)                                        │
│   380 │   │   │   if isinstance(do, DoAttempt):                                                  │
│   381 │   │   │   │   try:                                                                       │
│   382 │   │   │   │   │   result = fn(*args, **kwargs)                                           │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:314 in iter                          │
│                                                                                                  │
│   311 │   │                                                                                      │
│   312 │   │   is_explicit_retry = fut.failed and isinstance(fut.exception(), TryAgain)           │
│   313 │   │   if not (is_explicit_retry or self.retry(retry_state)):                             │
│ ❱ 314 │   │   │   return fut.result()                                                            │
│   315 │   │                                                                                      │
│   316 │   │   if self.after is not None:                                                         │
│   317 │   │   │   self.after(retry_state)                                                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/concurrent/futures/_base.py:439 in result                               │
│                                                                                                  │
│   436 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:                     │
│   437 │   │   │   │   │   raise CancelledError()                                                 │
│   438 │   │   │   │   elif self._state == FINISHED:                                              │
│ ❱ 439 │   │   │   │   │   return self.__get_result()                                             │
│   440 │   │   │   │                                                                              │
│   441 │   │   │   │   self._condition.wait(timeout)                                              │
│   442                                                                                            │
│                                                                                                  │
│ /usr/local/lib/python3.9/concurrent/futures/_base.py:391 in __get_result                         │
│                                                                                                  │
│   388 │   def __get_result(self):                                                                │
│   389 │   │   if self._exception:                                                                │
│   390 │   │   │   try:                                                                           │
│ ❱ 391 │   │   │   │   raise self._exception                                                      │
│   392 │   │   │   finally:                                                                       │
│   393 │   │   │   │   # Break a reference cycle with the exception in self._exception            │
│   394 │   │   │   │   self = None                                                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:382 in __call__                      │
│                                                                                                  │
│   379 │   │   │   do = self.iter(retry_state=retry_state)                                        │
│   380 │   │   │   if isinstance(do, DoAttempt):                                                  │
│   381 │   │   │   │   try:                                                                       │
│ ❱ 382 │   │   │   │   │   result = fn(*args, **kwargs)                                           │
│   383 │   │   │   │   except BaseException:  # noqa: B902                                        │
│   384 │   │   │   │   │   retry_state.set_exception(sys.exc_info())  # type: ignore[arg-type]    │
│   385 │   │   │   │   else:                                                                      │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:246 in                       │
│ _search_matching_campsites_available                                                             │
│                                                                                                  │
│    243 │   │   List[AvailableCampsite]                                                           │
│    244 │   │   """                                                                               │
│    245 │   │   matching_campgrounds = []                                                         │
│ ❱  246 │   │   for camp in self.get_all_campsites():                                             │
│    247 │   │   │   if all(                                                                       │
│    248 │   │   │   │   [                                                                         │
│    249 │   │   │   │   │   self._compare_date_overlap(campsite=camp) is True,                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/search_usedirect.py:128 in                  │
│ get_all_campsites                                                                                │
│                                                                                                  │
│   125 │   │   │   │   │   f"{month.strftime('%B, %Y')}"                                          │
│   126 │   │   │   │   )                                                                          │
│   127 │   │   │   │   end_date = month + relativedelta(months=1) - timedelta(days=1)             │
│ ❱ 128 │   │   │   │   campsites = self.campsite_finder.get_campsites(                            │
│   129 │   │   │   │   │   campground_id=campground.facility_id,                                  │
│   130 │   │   │   │   │   start_date=month,                                                      │
│   131 │   │   │   │   │   end_date=end_date,                                                     │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:385 in            │
│ get_campsites                                                                                    │
│                                                                                                  │
│   382 │   │   List[AvailableCampsite]                                                            │
│   383 │   │   """                                                                                │
│   384 │   │   self.refresh_metadata()                                                            │
│ ❱ 385 │   │   availability_response = self.get_campsites_response(                               │
│   386 │   │   │   campground_id=campground_id,                                                   │
│   387 │   │   │   start_date=start_date,                                                         │
│   388 │   │   │   end_date=end_date,                                                             │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/ratelimit/decorators.py:113 in wrapper                    │
│                                                                                                  │
│   110 │   │   '''                                                                                │
│   111 │   │   while True:                                                                        │
│   112 │   │   │   try:                                                                           │
│ ❱ 113 │   │   │   │   return func(*args, **kargs)                                                │
│   114 │   │   │   except RateLimitException as exception:                                        │
│   115 │   │   │   │   time.sleep(exception.period_remaining)                                     │
│   116 │   return wrapper                                                                         │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/ratelimit/decorators.py:80 in wrapper                     │
│                                                                                                  │
│    77 │   │   │   │   │   │   raise RateLimitException('too many calls', period_remaining)       │
│    78 │   │   │   │   │   return                                                                 │
│    79 │   │   │                                                                                  │
│ ❱  80 │   │   │   return func(*args, **kargs)                                                    │
│    81 │   │   return wrapper                                                                     │
│    82 │                                                                                          │
│    83 │   def __period_remaining(self):                                                          │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:336 in            │
│ get_campsites_response                                                                           │
│                                                                                                  │
│   333 │   │   │   )                                                                              │
│   334 │   │   │   if "Message" in response_json:                                                 │
│   335 │   │   │   │   error_message += " " + response_json["Message"]                            │
│ ❱ 336 │   │   │   raise UseDirectError(error_message) from e                                     │
│   337 │                                                                                          │
│   338 │   def get_campsites(                                                                     │
│   339 │   │   self,                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
UseDirectError: Error Parsing UseDirect Availability Response - Facility ID # 737. Invalid FacilityId specified for facility grid search on CALIRDR6

The above exception was the direct cause of the following exception:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/bin/camply:8 in <module>                                                              │
│                                                                                                  │
│   5 from camply.cli import cli                                                                   │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(cli())                                                                          │
│   9                                                                                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/cli.py:834 in cli                                  │
│                                                                                                  │
│   831 │   Camply Command Line Utility Wrapper                                                    │
│   832 │   """                                                                                    │
│   833 │   try:                                                                                   │
│ ❱ 834 │   │   camply_command_line()                                                              │
│   835 │   except KeyboardInterrupt:                                                              │
│   836 │   │   logger.debug("Handling Exit Request")                                              │
│   837 │   finally:                                                                               │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1130 in __call__                            │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/rich_click/rich_group.py:21 in main                       │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1055 in main                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1657 in invoke                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1404 in invoke                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:760 in invoke                               │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/decorators.py:38 in new_func                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/cli.py:726 in campsites                            │
│                                                                                                  │
│   723 │   │   }                                                                                  │
│   724 │   provider_class: Type[BaseCampingSearch] = CAMPSITE_SEARCH_PROVIDER[provider]           │
│   725 │   camping_finder: BaseCampingSearch = provider_class(**provider_kwargs)                  │
│ ❱ 726 │   camping_finder.get_matching_campsites(**search_kwargs)                                 │
│   727                                                                                            │
│   728                                                                                            │
│   729 @camply_command_line.command(cls=RichCommand)                                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:584 in                       │
│ get_matching_campsites                                                                           │
│                                                                                                  │
│    581 │   │   │   │   │   search_once=search_once,                                              │
│    582 │   │   │   │   )                                                                         │
│    583 │   │   │   except Exception as e:                                                        │
│ ❱  584 │   │   │   │   self.notifier.last_gasp(error=e)                                          │
│    585 │   │   │   │   raise e                                                                   │
│    586 │   │   else:                                                                             │
│    587 │   │   │   starting_count = len(self.campsites_found)                                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/notifications/multi_provider_notifications.py:127  │
│ in last_gasp                                                                                     │
│                                                                                                  │
│   124 │   │   )                                                                                  │
│   125 │   │   for provider in self.providers:                                                    │
│   126 │   │   │   provider.send_message(error_message)                                           │
│ ❱ 127 │   │   raise RuntimeError(error_message) from error                                       │
│   128                                                                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
RuntimeError: camply encountered an error and exited 😟 [2023-06-06 05:18:27] - (UseDirectError) Error Parsing UseDirect Availability Response - Facility ID # 737. 
Invalid FacilityId specified for facility grid search on CALIRDR6

Another example:

2023-06-06 05:59:16,527 [  CAMPLY]: camply, the campsite finder ⛺️
2023-06-06 05:59:16,528 [    INFO]: Using Camply Provider: "ReserveCalifornia"
2023-06-06 05:59:16,533 [    INFO]: 1 booking nights selected for search, ranging from 2023-06-10 to 2023-06-10
2023-06-06 05:59:17,078 [    INFO]: Searching for campsites every 10 minutes. 
2023-06-06 05:59:17,078 [    INFO]: Notifications active via: <SilentNotifications>, <TelegramNotifications>
2023-06-06 05:59:17,078 [    INFO]: Searching across 3 campgrounds
2023-06-06 05:59:17,078 [    INFO]:     ⛰  Sunset SB (#726) - 🏕  Pines Hollow and Dunes Camp (Sites 38 – 90) (#734)
2023-06-06 05:59:17,078 [    INFO]:     ⛰  Sunset SB (#726) - 🏕  Sunset Group Area (#735)
2023-06-06 05:59:17,078 [    INFO]:     ⛰  Sunset SB (#726) - 🏕  South Camp (sites 1-37) (#737)
2023-06-06 05:59:17,078 [    INFO]: Searching Pines Hollow and Dunes Camp (Sites 38 – 90), Sunset SB (734) for availability: June, 2023
2023-06-06 05:59:17,113 [    INFO]: Exception encountered, emitting notification last gasp.
2023-06-06 05:59:17,809 [  CAMPLY]: Exiting camply 👋
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:328 in            │
│ get_campsites_response                                                                           │
│                                                                                                  │
│   325 │   │   response.raise_for_status()                                                        │
│   326 │   │   response_json = response.json()                                                    │
│   327 │   │   try:                                                                               │
│ ❱ 328 │   │   │   return UseDirectAvailabilityResponse(**response.json())                        │
│   329 │   │   except ValidationError as e:                                                       │
│   330 │   │   │   error_message = (                                                              │
│   331 │   │   │   │   "Error Parsing UseDirect Availability Response "                           │
│                                                                                                  │
│ in pydantic.main.BaseModel.__init__:341                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ValidationError: 10 validation errors for UseDirectAvailabilityResponse
Filters
  none is not an allowed value (type=type_error.none.not_allowed)
EndDate
  none is not an allowed value (type=type_error.none.not_allowed)
TimeZone
  none is not an allowed value (type=type_error.none.not_allowed)
TimeStamp
  none is not an allowed value (type=type_error.none.not_allowed)
UnitSort
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Name
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Description
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> Restrictions
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> SeasonDates
  none is not an allowed value (type=type_error.none.not_allowed)
Facility -> TrafficStatuses
  none is not an allowed value (type=type_error.none.not_allowed)

The above exception was the direct cause of the following exception:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:574 in                       │
│ get_matching_campsites                                                                           │
│                                                                                                  │
│    571 │   │   """                                                                               │
│    572 │   │   if continuous is True or search_once is True:                                     │
│    573 │   │   │   try:                                                                          │
│ ❱  574 │   │   │   │   self._search_campsites_continuous(                                        │
│    575 │   │   │   │   │   log=log,                                                              │
│    576 │   │   │   │   │   verbose=verbose,                                                      │
│    577 │   │   │   │   │   polling_interval=polling_interval,                                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:508 in                       │
│ _search_campsites_continuous                                                                     │
│                                                                                                  │
│    505 │   │   continuous_search_attempts = 1                                                    │
│    506 │   │   while continuous_search is True:                                                  │
│    507 │   │   │   starting_count = len(self.campsites_found)                                    │
│ ❱  508 │   │   │   self._continuous_search_retry(                                                │
│    509 │   │   │   │   log=log,                                                                  │
│    510 │   │   │   │   verbose=verbose,                                                          │
│    511 │   │   │   │   polling_interval=polling_interval,                                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:354 in                       │
│ _continuous_search_retry                                                                         │
│                                                                                                  │
│    351 │   │   │   retry=tenacity.retry_if_exception_type(CampsiteNotFoundError),                │
│    352 │   │   │   wait=tenacity.wait.wait_fixed(int(polling_interval_minutes) * 60),            │
│    353 │   │   )                                                                                 │
│ ❱  354 │   │   matching_campsites = retryer.__call__(                                            │
│    355 │   │   │   fn=self._search_matching_campsites_available,                                 │
│    356 │   │   │   log=False,                                                                    │
│    357 │   │   │   verbose=False,                                                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:379 in __call__                      │
│                                                                                                  │
│   376 │   │                                                                                      │
│   377 │   │   retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs)   │
│   378 │   │   while True:                                                                        │
│ ❱ 379 │   │   │   do = self.iter(retry_state=retry_state)                                        │
│   380 │   │   │   if isinstance(do, DoAttempt):                                                  │
│   381 │   │   │   │   try:                                                                       │
│   382 │   │   │   │   │   result = fn(*args, **kwargs)                                           │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:314 in iter                          │
│                                                                                                  │
│   311 │   │                                                                                      │
│   312 │   │   is_explicit_retry = fut.failed and isinstance(fut.exception(), TryAgain)           │
│   313 │   │   if not (is_explicit_retry or self.retry(retry_state)):                             │
│ ❱ 314 │   │   │   return fut.result()                                                            │
│   315 │   │                                                                                      │
│   316 │   │   if self.after is not None:                                                         │
│   317 │   │   │   self.after(retry_state)                                                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/concurrent/futures/_base.py:439 in result                               │
│                                                                                                  │
│   436 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:                     │
│   437 │   │   │   │   │   raise CancelledError()                                                 │
│   438 │   │   │   │   elif self._state == FINISHED:                                              │
│ ❱ 439 │   │   │   │   │   return self.__get_result()                                             │
│   440 │   │   │   │                                                                              │
│   441 │   │   │   │   self._condition.wait(timeout)                                              │
│   442                                                                                            │
│                                                                                                  │
│ /usr/local/lib/python3.9/concurrent/futures/_base.py:391 in __get_result                         │
│                                                                                                  │
│   388 │   def __get_result(self):                                                                │
│   389 │   │   if self._exception:                                                                │
│   390 │   │   │   try:                                                                           │
│ ❱ 391 │   │   │   │   raise self._exception                                                      │
│   392 │   │   │   finally:                                                                       │
│   393 │   │   │   │   # Break a reference cycle with the exception in self._exception            │
│   394 │   │   │   │   self = None                                                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/tenacity/__init__.py:382 in __call__                      │
│                                                                                                  │
│   379 │   │   │   do = self.iter(retry_state=retry_state)                                        │
│   380 │   │   │   if isinstance(do, DoAttempt):                                                  │
│   381 │   │   │   │   try:                                                                       │
│ ❱ 382 │   │   │   │   │   result = fn(*args, **kwargs)                                           │
│   383 │   │   │   │   except BaseException:  # noqa: B902                                        │
│   384 │   │   │   │   │   retry_state.set_exception(sys.exc_info())  # type: ignore[arg-type]    │
│   385 │   │   │   │   else:                                                                      │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:246 in                       │
│ _search_matching_campsites_available                                                             │
│                                                                                                  │
│    243 │   │   List[AvailableCampsite]                                                           │
│    244 │   │   """                                                                               │
│    245 │   │   matching_campgrounds = []                                                         │
│ ❱  246 │   │   for camp in self.get_all_campsites():                                             │
│    247 │   │   │   if all(                                                                       │
│    248 │   │   │   │   [                                                                         │
│    249 │   │   │   │   │   self._compare_date_overlap(campsite=camp) is True,                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/search_usedirect.py:128 in                  │
│ get_all_campsites                                                                                │
│                                                                                                  │
│   125 │   │   │   │   │   f"{month.strftime('%B, %Y')}"                                          │
│   126 │   │   │   │   )                                                                          │
│   127 │   │   │   │   end_date = month + relativedelta(months=1) - timedelta(days=1)             │
│ ❱ 128 │   │   │   │   campsites = self.campsite_finder.get_campsites(                            │
│   129 │   │   │   │   │   campground_id=campground.facility_id,                                  │
│   130 │   │   │   │   │   start_date=month,                                                      │
│   131 │   │   │   │   │   end_date=end_date,                                                     │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:385 in            │
│ get_campsites                                                                                    │
│                                                                                                  │
│   382 │   │   List[AvailableCampsite]                                                            │
│   383 │   │   """                                                                                │
│   384 │   │   self.refresh_metadata()                                                            │
│ ❱ 385 │   │   availability_response = self.get_campsites_response(                               │
│   386 │   │   │   campground_id=campground_id,                                                   │
│   387 │   │   │   start_date=start_date,                                                         │
│   388 │   │   │   end_date=end_date,                                                             │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/ratelimit/decorators.py:113 in wrapper                    │
│                                                                                                  │
│   110 │   │   '''                                                                                │
│   111 │   │   while True:                                                                        │
│   112 │   │   │   try:                                                                           │
│ ❱ 113 │   │   │   │   return func(*args, **kargs)                                                │
│   114 │   │   │   except RateLimitException as exception:                                        │
│   115 │   │   │   │   time.sleep(exception.period_remaining)                                     │
│   116 │   return wrapper                                                                         │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/ratelimit/decorators.py:80 in wrapper                     │
│                                                                                                  │
│    77 │   │   │   │   │   │   raise RateLimitException('too many calls', period_remaining)       │
│    78 │   │   │   │   │   return                                                                 │
│    79 │   │   │                                                                                  │
│ ❱  80 │   │   │   return func(*args, **kargs)                                                    │
│    81 │   │   return wrapper                                                                     │
│    82 │                                                                                          │
│    83 │   def __period_remaining(self):                                                          │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/providers/usedirect/usedirect.py:336 in            │
│ get_campsites_response                                                                           │
│                                                                                                  │
│   333 │   │   │   )                                                                              │
│   334 │   │   │   if "Message" in response_json:                                                 │
│   335 │   │   │   │   error_message += " " + response_json["Message"]                            │
│ ❱ 336 │   │   │   raise UseDirectError(error_message) from e                                     │
│   337 │                                                                                          │
│   338 │   def get_campsites(                                                                     │
│   339 │   │   self,                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
UseDirectError: Error Parsing UseDirect Availability Response - Facility ID # 734. Invalid FacilityId specified for facility grid search on CALIRDR6

The above exception was the direct cause of the following exception:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/bin/camply:8 in <module>                                                              │
│                                                                                                  │
│   5 from camply.cli import cli                                                                   │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(cli())                                                                          │
│   9                                                                                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/cli.py:834 in cli                                  │
│                                                                                                  │
│   831 │   Camply Command Line Utility Wrapper                                                    │
│   832 │   """                                                                                    │
│   833 │   try:                                                                                   │
│ ❱ 834 │   │   camply_command_line()                                                              │
│   835 │   except KeyboardInterrupt:                                                              │
│   836 │   │   logger.debug("Handling Exit Request")                                              │
│   837 │   finally:                                                                               │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1130 in __call__                            │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/rich_click/rich_group.py:21 in main                       │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1055 in main                                │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1657 in invoke                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:1404 in invoke                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/core.py:760 in invoke                               │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/click/decorators.py:38 in new_func                        │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/cli.py:726 in campsites                            │
│                                                                                                  │
│   723 │   │   }                                                                                  │
│   724 │   provider_class: Type[BaseCampingSearch] = CAMPSITE_SEARCH_PROVIDER[provider]           │
│   725 │   camping_finder: BaseCampingSearch = provider_class(**provider_kwargs)                  │
│ ❱ 726 │   camping_finder.get_matching_campsites(**search_kwargs)                                 │
│   727                                                                                            │
│   728                                                                                            │
│   729 @camply_command_line.command(cls=RichCommand)                                              │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/search/base_search.py:584 in                       │
│ get_matching_campsites                                                                           │
│                                                                                                  │
│    581 │   │   │   │   │   search_once=search_once,                                              │
│    582 │   │   │   │   )                                                                         │
│    583 │   │   │   except Exception as e:                                                        │
│ ❱  584 │   │   │   │   self.notifier.last_gasp(error=e)                                          │
│    585 │   │   │   │   raise e                                                                   │
│    586 │   │   else:                                                                             │
│    587 │   │   │   starting_count = len(self.campsites_found)                                    │
│                                                                                                  │
│ /usr/local/lib/python3.9/site-packages/camply/notifications/multi_provider_notifications.py:127  │
│ in last_gasp                                                                                     │
│                                                                                                  │
│   124 │   │   )                                                                                  │
│   125 │   │   for provider in self.providers:                                                    │
│   126 │   │   │   provider.send_message(error_message)                                           │
│ ❱ 127 │   │   raise RuntimeError(error_message) from error                                       │
│   128                                                                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
RuntimeError: camply encountered an error and exited 😟 [2023-06-06 05:59:17] - (UseDirectError) Error Parsing UseDirect Availability Response - Facility ID # 734. 
Invalid FacilityId specified for facility grid search on CALIRDR6

Additional context

< Add any other context about the problem here. >

Add client support for APIs that require javascript and recent user agents

Is your feature request related to a problem? Please describe.
Some providers require up to date user agents to be presented or javascript to be available when making API requests. Let's investigate how to concisely present recent browser user agents and present the presence of javascript when making API requests to providers.

Describe the solution you'd like

  • All client requests rotate through a list of recent (Last two major versions) browser agents when setting the User-Agent header
  • All client requests support javascript (or at least meet the requirement that javascript is enabled)

A strong contender for providing this support: https://github.com/psf/requests-html

Describe alternatives you've considered
N/A

Additional context
#177

Incorrect Docker .camply location

Describe the bug

Docs show .camply location for Docker at /home/camply/.camply but right now it seems to be reading it from /root/.camply:

Original Camply Command (with --debug)

docker run \
  --name camply-file-share-example \
  --env TZ="America/Denver" \
  --volume ${HOME}/.camply:/home/camply/.camply \
  juftin/camply \
  camply campsites \
      --provider yellowstone \
      --start-date 2023-07-22 \
      --end-date 2023-07-27 \
      --continuous \
      --notifications email

Expected behavior
Should run with configuration from ${HOME}/.camply

Actual behavior

Configuration from ${HOME}/.camply are not used

Additional context

I checked an instance and when using camply configure from inside the Docker instance it creates it to /root/.camply and references it from there

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.