Skip to content

Commit 440acf1

Browse files
authored
Remove Google Drive export functionality (#77), Closes #76
1 parent 265df3b commit 440acf1

4 files changed

Lines changed: 21 additions & 133 deletions

File tree

README.md

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ This change was unannounced and no reason was ever released.
2020

2121
fb2cal is a tool which restores this functionality.
2222
It works by calling various async endpoints that power the https://www.facebook.com/events/birthdays/ page.
23-
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).
24-
The ICS file can also be stored on the local file system.
23+
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).
2524

2625
This tool **does not** use the Facebook API.
2726

@@ -30,10 +29,8 @@ This tool **does not** use the Facebook API.
3029
* Python 3.6+
3130
* pipenv
3231
* Scheduler tool to automatically run script periodically (optional)
33-
* Google Drive API access (optional)
3432

3533
## Instructions
36-
### Option 1: Save ICS file to filesystem
3734
1. Clone repo
3835
`git clone git@github.com:mobeigi/fb2cal.git`
3936
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.
4239
4. Run the script manually:
4340
`pipenv run python src/fb2cal.py`
4441
5. Import the created `birthdays.ics` file into Calendar applications (i.e. Google Calendar)
45-
### Option 2: Automatically Upload ICS file to Google Drive
46-
1. Clone repo
47-
`git clone git@github.com:mobeigi/fb2cal.git`
48-
2. Create a Google Drive API credentials
49-
1. Visit the Google Drive APIs page: https://console.developers.google.com/apis/api/drive.googleapis.com/overview
50-
2. Create a new project (if you don't already have one)
51-
3. Enable API (if not already enabled)
52-
4. Select **API & Services** > **Credentials** from left pane.
53-
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)
54-
6. Click **Create** to create your OAuth client ID credentials
55-
7. Download credentials JSON file
56-
3. Rename credentials JSON file to **credentials.json** and put it in the `src` folder
57-
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.
58-
5. Install required python modules
59-
`pipenv install`
60-
1. Run script manually once for testing purposes:
61-
`pipenv run python ./fb2cal.py`
62-
7. Check Google Drive to ensure your ICS file was made.
63-
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.
64-
9. Use the following link to import your ICS file into Calendar applications (i.e. Google Calendar):
65-
`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.
6642

6743
## Configuration
6844
This tool can be configured by editing the `config/config.ini` configuration file.
6945

70-
<table> <thead> <tr style="background-color: inherit"> <th>Section</th> <th>Key</th> <th>Valid Values</th> <th>Description</th> </tr></thead> <tbody> <tr style="background-color: inherit"> <td rowspan=2>AUTH</td><td>fb_email</td><td></td><td>Your Facebook login email</td></tr><tr style="background-color: inherit"> <td>fb_password</td><td></td><td>Your Facebook login password</td></tr><tr style="background-color: inherit"> <td rowspan=3>DRIVE</td><td>upload_to_drive</td><td>True, False</td><td>If tool should automatically upload ICS file to Google Drive</td></tr><tr style="background-color: inherit"> <td>drive_file_id</td><td></td><td>The file id of file to write to on Google Drive. Leave blank to create a new file for the first time.</td></tr><tr style="background-color: inherit"> <td>ics_file_name</td><td></td><td>The name of the file to be stored/updated on Google Drive.</td></tr><tr style="background-color: inherit"> <td rowspan=2>FILESYSTEM</td><td>save_to_file</td><td>True, False</td><td>If tool should save ICS file to the local file system</td></tr><tr style="background-color: inherit"> <td>ics_file_path</td><td></td><td>Path to save ICS file to (including file name)</td></tr><tr style="background-color: inherit"> <td>LOGGING</td><td>level</td><td>DEBUG, INFO, WARNING, ERROR, CRITICAL</td><td>Logging level to use. Default: INFO</td></tr></tbody></table>
46+
<table> <thead> <tr> <th>Section</th> <th>Key</th> <th>Valid Values</th> <th>Description</th> </tr></thead> <tbody> <tr> <td rowspan=2>AUTH</td><td>fb_email</td><td></td><td>Your Facebook login email</td></tr><tr> <td>fb_password</td><td></td><td>Your Facebook login password</td></tr><tr> <td rowspan=2>FILESYSTEM</td><td>save_to_file</td><td>True, False</td><td>If tool should save ICS file to the local file system</td></tr><tr> <td>ics_file_path</td><td></td><td>Path to save ICS file to (including file name)</td></tr><tr> <td>LOGGING</td><td>level</td><td>DEBUG, INFO, WARNING, ERROR, CRITICAL</td><td>Logging level to use. Default: INFO</td></tr></tbody></table>
7147

7248
## Troubleshooting
7349
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.

config/config-template.ini

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1-
; Rename this file to config.ini and fill in required information below
2-
[AUTH]
3-
fb_email =
4-
fb_pass =
5-
6-
[DRIVE]
7-
upload_to_drive = False
8-
drive_file_id =
9-
ics_file_name = birthdays.ics
10-
11-
[FILESYSTEM]
12-
save_to_file = True
13-
ics_file_path = ./birthdays.ics
14-
15-
[LOGGING]
16-
level = INFO
1+
; Rename this file to config.ini and fill in required information below
2+
[AUTH]
3+
fb_email =
4+
fb_pass =
5+
6+
[FILESYSTEM]
7+
save_to_file = True
8+
ics_file_path = ./birthdays.ics
9+
10+
[LOGGING]
11+
level = INFO

requirements.txt

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
MechanicalSoup
2-
ics>=0.6
3-
babel
4-
pytz
5-
httplib2
6-
requests
7-
beautifulsoup4
8-
lxml
9-
python_dateutil
10-
google_api_python_client
11-
google-auth-oauthlib
12-
oauth2client
1+
MechanicalSoup
2+
ics>=0.6
3+
babel
4+
pytz
5+
requests
6+
beautifulsoup4
7+
lxml
8+
python_dateutil

src/fb2cal.py

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,6 @@
4343
from distutils import util
4444
import calendar
4545

46-
from oauth2client import file, client, tools
47-
from googleapiclient.discovery import build
48-
from googleapiclient.http import MediaIoBaseUpload
49-
from googleapiclient.errors import HttpError
50-
from httplib2 import Http
51-
from io import BytesIO
52-
5346
# Classes
5447
class Birthday:
5548
def __init__(self, uid, name, day, month):
@@ -98,12 +91,6 @@ def main():
9891

9992
logger.info(f'Logging level set to: {logging.getLevelName(logger.level)}')
10093

101-
# Authenticate with Google API early
102-
if util.strtobool(config['DRIVE']['UPLOAD_TO_DRIVE']):
103-
logger.info('Authenticating with Google Drive API...')
104-
service = google_drive_api_authenticate()
105-
logger.info('Successfully authenticated with Google Drive API.')
106-
10794
# Init browser
10895
browser = mechanicalsoup.StatefulBrowser()
10996
init_browser(browser)
@@ -143,37 +130,6 @@ def main():
143130
ics_file.write(ics_str)
144131
logger.info(f'Successfully saved ICS file to {os.path.abspath(config["FILESYSTEM"]["ICS_FILE_PATH"])}')
145132

146-
# Upload to drive
147-
if util.strtobool(config['DRIVE']['UPLOAD_TO_DRIVE']):
148-
logger.info('Uploading ICS file to Google Drive...')
149-
metadata = {'name': config['DRIVE']['ICS_FILE_NAME']}
150-
UPLOAD_RETRY_ATTEMPTS = 3
151-
uploaded_successfully = False
152-
153-
for attempt in range(UPLOAD_RETRY_ATTEMPTS):
154-
try:
155-
updated_file = upload_and_replace_file(service, config['DRIVE']['DRIVE_FILE_ID'], metadata, bytearray(ics_str, 'utf-8')) # Pass payload as bytes
156-
config.set('DRIVE', 'DRIVE_FILE_ID', updated_file['id'])
157-
uploaded_successfully = True
158-
except HttpError as e:
159-
if e.resp.status == 404: # file not found
160-
if config['DRIVE']['DRIVE_FILE_ID']:
161-
logger.warning(f'{e}. Resetting stored file id in config and trying again. Attempt: {attempt+1}')
162-
config.set('DRIVE', 'DRIVE_FILE_ID', '') # reset stored file_id
163-
continue
164-
else:
165-
logger.error(e)
166-
raise SystemError
167-
else:
168-
logger.error(e)
169-
raise SystemError
170-
171-
if uploaded_successfully:
172-
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"]}')
173-
else:
174-
logger.error(f'Failed to upload {config["DRIVE"]["ICS_FILE_NAME"]} to Google Drive after {UPLOAD_RETRY_ATTEMPTS} attempts.')
175-
raise SystemError
176-
177133
# Update config file with updated file id for subsequent runs
178134
logger.info('Saving changes to config file...')
179135
with open(CONFIG_FILE_PATH, 'w') as configfile:
@@ -262,41 +218,6 @@ def facebook_authenticate(browser, email, password):
262218
logger.error(f'Hit Facebook security checkpoint. Please login to Facebook manually and follow prompts to authorize this device.')
263219
raise SystemError
264220

265-
def google_drive_api_authenticate():
266-
""" Authenticate with Google Drive Api """
267-
268-
# Confirm credentials.json exists
269-
if not os.path.isfile('credentials.json'):
270-
logger.error(f'credentials.json file does not exist')
271-
raise SystemExit
272-
273-
SCOPES = 'https://www.googleapis.com/auth/drive.file'
274-
store = file.Storage('token.json')
275-
creds = store.get()
276-
if not creds or creds.invalid:
277-
flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
278-
creds = tools.run_flow(flow, store)
279-
service = build('drive', 'v3', http=creds.authorize(Http()), cache_discovery=False)
280-
return service
281-
282-
def upload_and_replace_file(service, file_id, metadata, payload):
283-
mine_type = 'text/calendar'
284-
text_stream = BytesIO(payload)
285-
media_body = MediaIoBaseUpload(text_stream, mimetype=mine_type, chunksize=1024*1024, resumable=True)
286-
287-
# If file id is provided, update the file, otherwise we'll create a new file
288-
if file_id:
289-
updated_file = service.files().update(fileId=file_id, body=metadata, media_body=media_body).execute()
290-
else:
291-
updated_file = service.files().create(body=metadata, media_body=media_body).execute()
292-
293-
# Need publically accessible ics file so third party tools can read from it publically
294-
permission = { "role": 'reader',
295-
"type": 'anyone'}
296-
service.permissions().create(fileId=updated_file['id'], body=permission).execute()
297-
298-
return updated_file
299-
300221
__cached_async_token = None
301222
def get_async_token(browser):
302223
""" Get async authorization token (CSRF protection token) that must be included in all async requests """

0 commit comments

Comments
 (0)