diff --git a/README.md b/README.md
index 3b67268..beba684 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,7 @@ This change was unannounced and no reason was ever released.
fb2cal is a tool which restores this functionality.
It works by calling various async endpoints that power the https://www.facebook.com/events/birthdays/ page.
-After gathering a list of birthdays for all the users friends for a full year, it creates a ICS calendar file which is then stored on Google Drive as a publically shared file. This ICS file can then be imported into third party tools (such as Google Calendar).
-The ICS file can also be stored on the local file system.
+After gathering a list of birthdays for all the users friends for a full year, it creates a ICS calendar file. This ICS file can then be imported into third party tools (such as Google Calendar).
This tool **does not** use the Facebook API.
@@ -30,10 +29,8 @@ This tool **does not** use the Facebook API.
* Python 3.6+
* pipenv
* Scheduler tool to automatically run script periodically (optional)
-* Google Drive API access (optional)
## Instructions
-### Option 1: Save ICS file to filesystem
1. Clone repo
`git clone git@github.com:mobeigi/fb2cal.git`
2. Rename `config/config-template.ini` to `config/config.ini` and enter your Facebook email and password (no quotes).
@@ -42,32 +39,11 @@ This tool **does not** use the Facebook API.
4. Run the script manually:
`pipenv run python src/fb2cal.py`
5. Import the created `birthdays.ics` file into Calendar applications (i.e. Google Calendar)
-### Option 2: Automatically Upload ICS file to Google Drive
-1. Clone repo
-`git clone git@github.com:mobeigi/fb2cal.git`
-2. Create a Google Drive API credentials
- 1. Visit the Google Drive APIs page: https://console.developers.google.com/apis/api/drive.googleapis.com/overview
- 2. Create a new project (if you don't already have one)
- 3. Enable API (if not already enabled)
- 4. Select **API & Services** > **Credentials** from left pane.
- 5. Select **Create Credentials** > **OAuth client ID**. Make sure to **Configure content screen** if you are prompted to do so. For the application type select **Other** and then enter any name you like (i.e. fb2cal)
- 6. Click **Create** to create your OAuth client ID credentials
- 7. Download credentials JSON file
-3. Rename credentials JSON file to **credentials.json** and put it in the `src` folder
-4. Rename `config/config-template.ini` to `config/config.ini` and enter your Facebook email and password as well as a name for your calender to be saved on Google Drive. Change `upload_to_drive` to `True`. Initially, the value for the **drive_file_id** field should be empty.
-5. Install required python modules
-`pipenv install`
-1. Run script manually once for testing purposes:
-`pipenv run python ./fb2cal.py`
-7. Check Google Drive to ensure your ICS file was made.
-8. Setup Cron Jobs/Task Scheduler/Automator to repeatedly run the script to periodically generate an updated ICS file. See **Scheduled Task Frequency** section for more info.
-9. Use the following link to import your ICS file into Calendar applications (i.e. Google Calendar):
-`http://drive.google.com/uc?export=download&id=DRIVE_FILE_ID`. Replace **DRIVE_FILE_ID** with the autopopulated value found in your `config/config.ini` file.
## Configuration
This tool can be configured by editing the `config/config.ini` configuration file.
-
Section | Key | Valid Values | Description |
AUTH | fb_email | | Your Facebook login email |
fb_password | | Your Facebook login password |
DRIVE | upload_to_drive | True, False | If tool should automatically upload ICS file to Google Drive |
drive_file_id | | The file id of file to write to on Google Drive. Leave blank to create a new file for the first time. |
ics_file_name | | The name of the file to be stored/updated on Google Drive. |
FILESYSTEM | save_to_file | True, False | If tool should save ICS file to the local file system |
ics_file_path | | Path to save ICS file to (including file name) |
LOGGING | level | DEBUG, INFO, WARNING, ERROR, CRITICAL | Logging level to use. Default: INFO |
+ Section | Key | Valid Values | Description |
AUTH | fb_email | | Your Facebook login email |
fb_password | | Your Facebook login password |
FILESYSTEM | save_to_file | True, False | If tool should save ICS file to the local file system |
ics_file_path | | Path to save ICS file to (including file name) |
LOGGING | level | DEBUG, INFO, WARNING, ERROR, CRITICAL | Logging level to use. Default: INFO |
## Troubleshooting
If you encounter any issues, please open the `config/config.ini` configuration file and set the `LOGGING` `level` to `DEBUG` (it is `INFO` by default). Include these logs when asking for help.
diff --git a/config/config-template.ini b/config/config-template.ini
index 150c0b7..60d0465 100644
--- a/config/config-template.ini
+++ b/config/config-template.ini
@@ -1,16 +1,11 @@
-; Rename this file to config.ini and fill in required information below
-[AUTH]
-fb_email =
-fb_pass =
-
-[DRIVE]
-upload_to_drive = False
-drive_file_id =
-ics_file_name = birthdays.ics
-
-[FILESYSTEM]
-save_to_file = True
-ics_file_path = ./birthdays.ics
-
-[LOGGING]
-level = INFO
+; Rename this file to config.ini and fill in required information below
+[AUTH]
+fb_email =
+fb_pass =
+
+[FILESYSTEM]
+save_to_file = True
+ics_file_path = ./birthdays.ics
+
+[LOGGING]
+level = INFO
diff --git a/requirements.txt b/requirements.txt
index 8b87050..ab8d645 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,12 +1,8 @@
-MechanicalSoup
-ics>=0.6
-babel
-pytz
-httplib2
-requests
-beautifulsoup4
-lxml
-python_dateutil
-google_api_python_client
-google-auth-oauthlib
-oauth2client
\ No newline at end of file
+MechanicalSoup
+ics>=0.6
+babel
+pytz
+requests
+beautifulsoup4
+lxml
+python_dateutil
\ No newline at end of file
diff --git a/src/fb2cal.py b/src/fb2cal.py
index 0bf44dd..70ee510 100644
--- a/src/fb2cal.py
+++ b/src/fb2cal.py
@@ -43,13 +43,6 @@
from distutils import util
import calendar
-from oauth2client import file, client, tools
-from googleapiclient.discovery import build
-from googleapiclient.http import MediaIoBaseUpload
-from googleapiclient.errors import HttpError
-from httplib2 import Http
-from io import BytesIO
-
# Classes
class Birthday:
def __init__(self, uid, name, day, month):
@@ -98,12 +91,6 @@ def main():
logger.info(f'Logging level set to: {logging.getLevelName(logger.level)}')
- # Authenticate with Google API early
- if util.strtobool(config['DRIVE']['UPLOAD_TO_DRIVE']):
- logger.info('Authenticating with Google Drive API...')
- service = google_drive_api_authenticate()
- logger.info('Successfully authenticated with Google Drive API.')
-
# Init browser
browser = mechanicalsoup.StatefulBrowser()
init_browser(browser)
@@ -143,37 +130,6 @@ def main():
ics_file.write(ics_str)
logger.info(f'Successfully saved ICS file to {os.path.abspath(config["FILESYSTEM"]["ICS_FILE_PATH"])}')
- # Upload to drive
- if util.strtobool(config['DRIVE']['UPLOAD_TO_DRIVE']):
- logger.info('Uploading ICS file to Google Drive...')
- metadata = {'name': config['DRIVE']['ICS_FILE_NAME']}
- UPLOAD_RETRY_ATTEMPTS = 3
- uploaded_successfully = False
-
- for attempt in range(UPLOAD_RETRY_ATTEMPTS):
- try:
- updated_file = upload_and_replace_file(service, config['DRIVE']['DRIVE_FILE_ID'], metadata, bytearray(ics_str, 'utf-8')) # Pass payload as bytes
- config.set('DRIVE', 'DRIVE_FILE_ID', updated_file['id'])
- uploaded_successfully = True
- except HttpError as e:
- if e.resp.status == 404: # file not found
- if config['DRIVE']['DRIVE_FILE_ID']:
- logger.warning(f'{e}. Resetting stored file id in config and trying again. Attempt: {attempt+1}')
- config.set('DRIVE', 'DRIVE_FILE_ID', '') # reset stored file_id
- continue
- else:
- logger.error(e)
- raise SystemError
- else:
- logger.error(e)
- raise SystemError
-
- if uploaded_successfully:
- logger.info(f'Successfully uploaded {config["DRIVE"]["ICS_FILE_NAME"]} to Google Drive with file id: {config["DRIVE"]["DRIVE_FILE_ID"]}\nDirect download link: http://drive.google.com/uc?export=download&id={config["DRIVE"]["DRIVE_FILE_ID"]}')
- else:
- logger.error(f'Failed to upload {config["DRIVE"]["ICS_FILE_NAME"]} to Google Drive after {UPLOAD_RETRY_ATTEMPTS} attempts.')
- raise SystemError
-
# Update config file with updated file id for subsequent runs
logger.info('Saving changes to config file...')
with open(CONFIG_FILE_PATH, 'w') as configfile:
@@ -262,41 +218,6 @@ def facebook_authenticate(browser, email, password):
logger.error(f'Hit Facebook security checkpoint. Please login to Facebook manually and follow prompts to authorize this device.')
raise SystemError
-def google_drive_api_authenticate():
- """ Authenticate with Google Drive Api """
-
- # Confirm credentials.json exists
- if not os.path.isfile('credentials.json'):
- logger.error(f'credentials.json file does not exist')
- raise SystemExit
-
- SCOPES = 'https://www.googleapis.com/auth/drive.file'
- store = file.Storage('token.json')
- creds = store.get()
- if not creds or creds.invalid:
- flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
- creds = tools.run_flow(flow, store)
- service = build('drive', 'v3', http=creds.authorize(Http()), cache_discovery=False)
- return service
-
-def upload_and_replace_file(service, file_id, metadata, payload):
- mine_type = 'text/calendar'
- text_stream = BytesIO(payload)
- media_body = MediaIoBaseUpload(text_stream, mimetype=mine_type, chunksize=1024*1024, resumable=True)
-
- # If file id is provided, update the file, otherwise we'll create a new file
- if file_id:
- updated_file = service.files().update(fileId=file_id, body=metadata, media_body=media_body).execute()
- else:
- updated_file = service.files().create(body=metadata, media_body=media_body).execute()
-
- # Need publically accessible ics file so third party tools can read from it publically
- permission = { "role": 'reader',
- "type": 'anyone'}
- service.permissions().create(fileId=updated_file['id'], body=permission).execute()
-
- return updated_file
-
__cached_async_token = None
def get_async_token(browser):
""" Get async authorization token (CSRF protection token) that must be included in all async requests """