-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8c3e7ac
commit 6430029
Showing
3 changed files
with
151 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
cachetools==5.2.0 | ||
certifi==2022.12.7 | ||
charset-normalizer==2.1.1 | ||
google-api-core==2.11.0 | ||
google-api-python-client==2.70.0 | ||
google-auth==2.15.0 | ||
google-auth-httplib2==0.1.0 | ||
google-auth-oauthlib==0.8.0 | ||
googleapis-common-protos==1.57.0 | ||
httplib2==0.21.0 | ||
idna==3.4 | ||
more-itertools==9.0.0 | ||
oauthlib==3.2.2 | ||
protobuf==4.21.12 | ||
pyasn1==0.4.8 | ||
pyasn1-modules==0.2.8 | ||
pyparsing==3.0.9 | ||
requests==2.28.1 | ||
requests-oauthlib==1.3.1 | ||
rsa==4.9 | ||
six==1.16.0 | ||
uritemplate==4.1.1 | ||
urllib3==1.26.13 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import csv | ||
import os | ||
import argparse | ||
import sys | ||
|
||
from more_itertools import grouper | ||
from googleapiclient.discovery import build | ||
|
||
|
||
MAX_RESULTS = 50 | ||
|
||
|
||
def get_video_ids(youtube, channel_id, published_after=None, published_before=None): | ||
""" | ||
Get a list of video IDs for a channel published between specified dates (optional). | ||
""" | ||
video_ids = [] | ||
next_page_token = "" | ||
|
||
while True: | ||
search_list = youtube.search().list( | ||
part="id", | ||
channelId=channel_id, | ||
type="video", | ||
order="date", | ||
publishedAfter=published_after, | ||
publishedBefore=published_before, | ||
maxResults=MAX_RESULTS, | ||
pageToken=next_page_token | ||
).execute() | ||
video_ids.extend([item["id"]["videoId"] | ||
for item in search_list["items"]]) | ||
next_page_token = search_list.get("nextPageToken") | ||
|
||
# If there is no next page, break the loop | ||
if not next_page_token: | ||
break | ||
return video_ids | ||
|
||
|
||
def get_video_data(youtube, video_ids): | ||
""" | ||
Get the view count, title, and video URL for a list of video IDs. | ||
""" | ||
video_data = [] | ||
|
||
# Iterate through the video IDs in chunks of MAX_RESULTS | ||
for video_ids_chunk in grouper(video_ids, MAX_RESULTS): | ||
# Remove None values from the final chunk | ||
video_ids_joined = ",".join( | ||
[x for x in video_ids_chunk if x is not None]) | ||
videos_list = youtube.videos().list( | ||
id=video_ids_joined, | ||
part="snippet,statistics" | ||
).execute() | ||
|
||
# Iterate through the video data and add it to the list | ||
for video in videos_list["items"]: | ||
video_data.append({ | ||
"Views": video["statistics"]["viewCount"], | ||
"Title": video["snippet"]["title"], | ||
"URL": f"https://www.youtube.com/watch?v={video['id']}" | ||
}) | ||
|
||
# Sort the video data by view count in descending order | ||
video_data.sort(key=lambda x: int(x["Views"]), reverse=True) | ||
|
||
return video_data | ||
|
||
|
||
def write_csv(video_data): | ||
""" | ||
Write the video data to STDOUT as CSV. | ||
""" | ||
with sys.stdout as csv_file: | ||
writer = csv.DictWriter(csv_file, fieldnames=["Views", "Title", "URL"]) | ||
writer.writeheader() | ||
writer.writerows(video_data) | ||
|
||
|
||
def get_inputs(): | ||
""" | ||
Get inputs from command line and environment variables. | ||
""" | ||
parser = argparse.ArgumentParser( | ||
description="Get YouTube video data for a channel between and write it out in CSV format.") | ||
parser.add_argument( | ||
"--channel", help="The ID of the YouTube channel to search.") | ||
parser.add_argument( | ||
"--after", help="The published after date to search from in the format YYYY-MM-DDTHH:MM:SSZ.", default=None) | ||
parser.add_argument( | ||
"--before", help="The published before date to search from in the format YYYY-MM-DDTHH:MM:SSZ.", default=None) | ||
args = parser.parse_args() | ||
|
||
return { | ||
"api_key": os.environ.get("APIKEY"), | ||
"channel": args.channel, | ||
"after": args.after, | ||
"before": args.before, | ||
} | ||
|
||
|
||
def main(): | ||
inputs = get_inputs() | ||
youtube = build("youtube", "v3", developerKey=inputs['api_key']) | ||
video_ids = get_video_ids( | ||
youtube, inputs['channel'], inputs['after'], inputs['before']) | ||
video_data = get_video_data(youtube, video_ids) | ||
write_csv(video_data) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |