-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscroll.py
More file actions
126 lines (102 loc) · 5.88 KB
/
Copy pathscroll.py
File metadata and controls
126 lines (102 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import argparse
import json
import pathlib
import shutil
import subprocess
import sys
from time import sleep
from google_auth_oauthlib import get_user_credentials
from google.auth.transport.requests import AuthorizedSession
from google.oauth2.credentials import Credentials
import requests
def main():
parser = argparse.ArgumentParser(description='A tool for fetching and scrolling images (and music) stored in Google Drive.')
parser.add_argument('--credential-store', required=True, help='Location of persistent credential store.')
parser.add_argument('--images-parent-id', required=True, help='Google Drive parent (folder) id that contains the child images.')
parser.add_argument('--music-parent-id', help='Google Drive parent (folder) id that contains the child music files.')
parser.add_argument('--no-connection-check', action='store_true', help='If used, will skip internet connection check.')
parser.add_argument('--slideshow-interval', default=10, help='Number of seconds between images. (default: 10)')
args = parser.parse_args()
# Check to see if we have internet access; if not, wait untill we get it.
if not args.no_connection_check:
while True:
try:
requests.get('https://www.google.com')
except: # pylint: disable=bare-except
sleep(15)
else:
break
# https://developers.google.com/drive/api/v3/about-auth
# https://google-auth.readthedocs.io/en/latest/user-guide.html#user-credentials
# Tool for checking access tokens: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=[TOKEN]
# pylint: disable=subprocess-run-check
# We are sending everything to the background anyway so using check won't affect anything.
credential_path = pathlib.Path(args.credential_store)
if credential_path.is_file():
with open(credential_path) as stream:
credentials_file = json.load(stream)
# When we create the Credentials object later using **kwargs, the object behaves odd when expiry is set at initialization so we delete it.
if 'expiry' in credentials_file:
del credentials_file['expiry']
else:
print('ERROR: Credential store provided is not a file')
sys.exit(1)
# Assume this is the first run and we need to go through the OAuth workflow.
if 'token' not in credentials_file:
try:
# https://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.html#google_auth_oauthlib.get_user_credentials
credentials = get_user_credentials(['https://www.googleapis.com/auth/drive.readonly'], credentials_file['client_id'], credentials_file['client_secret'])
except KeyError:
print('ERROR: Missing required keys (client_id or client_secret) in credential store.')
sys.exit(1)
else:
credentials = Credentials(**credentials_file)
# This requests Session object will handle token refresh and checking: https://google-auth.readthedocs.io/en/latest/reference/google.auth.transport.requests.html#google.auth.transport.requests.AuthorizedSession
session = AuthorizedSession(credentials)
# API: https://developers.google.com/drive/api/v3/reference/files/list
# Query structure: https://developers.google.com/drive/api/v3/search-files#query_string_examples
image_list = session.get(f'https://www.googleapis.com/drive/v3/files?supportsAllDrives=true&includeItemsFromAllDrives=true&q=\'{args.images_parent_id}\' in parents and trashed = false')
image_files = [file for file in image_list.json()['files'] if file['mimeType'].startswith('image')] # Images only, please.
# Example /files response:
# {
# "kind": "drive#fileList",
# "incompleteSearch": false,
# "files": [ ... ]
# }
images_dir = pathlib.Path('/tmp/gdrive-scroll/images')
# See if there are existing images; if so, remove the images directory and its content then create a new directory.
if images_dir.exists():
shutil.rmtree(images_dir)
images_dir.mkdir(parents=True)
for image in image_files:
# https://developers.google.com/drive/api/v3/reference/files/get
file = session.get(f'https://www.googleapis.com/drive/v3/files/{image["id"]}?alt=media')
# Example /files/ID response:
# {
# "kind": "drive#file",
# "id": "FOO",
# "name": "FOO.jpg",
# "mimeType": "image/jpeg"
# }
with open(pathlib.Path(images_dir, image['name']), 'wb') as stream:
stream.write(file.content)
subprocess.run(f'feh --slideshow-delay {args.slideshow_interval} {images_dir} &', shell=True)
# Do almost everything again but for music this time.
if args.music_parent_id:
music_list = session.get(f'https://www.googleapis.com/drive/v3/files?supportsAllDrives=true&includeItemsFromAllDrives=true&q=\'{args.music_parent_id}\' in parents and trashed = false')
music_files = [file for file in music_list.json()['files'] if file['mimeType'] == 'audio/mpeg'] # MPEG only, please.
print(music_list.json())
music_dir = pathlib.Path('/tmp/gdrive-scroll/music')
if music_dir.exists():
shutil.rmtree(music_dir)
music_dir.mkdir(parents=True)
for music in music_files:
file = session.get(f'https://www.googleapis.com/drive/v3/files/{music["id"]}?alt=media')
with open(pathlib.Path(music_dir, music['name']), 'wb') as stream:
stream.write(file.content)
subprocess.run(f'mpg123 --random {music_dir}/* &', shell=True)
# Write our final credential information for use later.
with open(credential_path, 'w') as stream:
json.dump(json.loads(credentials.to_json()), stream) # https://google-auth.readthedocs.io/en/stable/reference/google.oauth2.credentials.html#google.oauth2.credentials.Credentials.to_json
if __name__ == '__main__':
main()