summaryrefslogtreecommitdiffstats
path: root/webapi
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2024-04-13 01:08:10 -0700
committerPinapelz <yukais@pinapelz.com>2024-04-13 01:08:10 -0700
commit163e07adb573da8497c9ccf0ae97a6c261e7b14a (patch)
tree72c1763fbb76b8fc24b318ffa7c4028273ebf01b /webapi
initial commit. Migration from GitLab
Diffstat (limited to 'webapi')
-rw-r--r--webapi/holodex.py75
-rw-r--r--webapi/web_api.py29
-rw-r--r--webapi/youtube.py61
3 files changed, 165 insertions, 0 deletions
diff --git a/webapi/holodex.py b/webapi/holodex.py
new file mode 100644
index 0000000..5f81892
--- /dev/null
+++ b/webapi/holodex.py
@@ -0,0 +1,75 @@
+from webapi.web_api import WebAPI
+from typing import Iterable
+
+
+class HolodexAPI(WebAPI):
+ """
+ Class for interacting with the Holodex API
+ """
+
+ def __init__(self,api_key: str = None,member_count: int = 300,organization: str = "Nijisanji"):
+ super().__init__(api_key=api_key, base_url="https://holodex.net/api/v2/")
+ self.member_count = member_count
+ self.organization = organization
+ self._inactive_channels = []
+ self._channel_data = []
+
+ def get_subscriber_data(self) -> Iterable:
+ """
+ Gets data for all channels in a particular organization
+ """
+ members = self.member_count
+ data = []
+ active_channels = []
+ offset = 0
+ while members > 0:
+ data += self._download_url(
+ f"channels?type=vtuber&offset={offset}&limit=100&org={self.organization}"
+ )
+ members -= 100
+ offset += 100
+ for channel in data:
+ print("DEBUG: ", channel["id"])
+ try:
+ channel["description"] = self.get_channel_description(channel["id"])
+ if channel["inactive"]:
+ self._inactive_channels.append(channel["id"])
+ continue
+ active_channels.append(channel)
+ except (KeyError, TypeError, ValueError):
+ print("DEBUG:","An error occured with parsing ", channel["id"], channel["name"])
+ continue
+ self._channel_data = active_channels
+ return active_channels
+
+ def get_view_count(self, channel_id: str) -> int:
+ """
+ Gets the view count for a particular channel
+ """
+ data = self._download_url(f"channels/{channel_id}")
+ return data["view_count"]
+
+ def get_channel_description(self, channel_id: str) -> str:
+ """
+ Gets the description for a particular channel
+ """
+ data = self._download_url(f"channels/{channel_id}")
+ return data["description"]
+
+ def set_organization(self, organization: str):
+ """
+ Sets the organization for the API
+ """
+ self.organization = organization
+
+ def get_inactive_channels(self) -> list:
+ """
+ Gets the list of inactive channels
+ """
+ return self._inactive_channels
+
+ def get_generated_channel_data(self) -> list:
+ """
+ Gets the list of channel data
+ """
+ return self._channel_data
diff --git a/webapi/web_api.py b/webapi/web_api.py
new file mode 100644
index 0000000..525994c
--- /dev/null
+++ b/webapi/web_api.py
@@ -0,0 +1,29 @@
+import urllib.request
+import json
+
+
+class WebAPI:
+ """
+ General class for interacting with web APIs
+ """
+
+ def __init__(self, api_key: str, base_url: str) -> None:
+ self.api_key = api_key
+ self.base_url = base_url
+
+ def _download_url(self, query: str, header = 'X-APIKEY') -> dict:
+ """
+ Downloads the URL and returns the result as a string
+ param:
+ query: str - the query to be appended to the base URL
+ """
+ if self.api_key is None:
+ raise Exception("API key not set")
+ opener = urllib.request.build_opener()
+ opener.addheaders = [(header, self.api_key)]
+ urllib.request.install_opener(opener)
+ response = urllib.request.urlopen(self.base_url + query)
+ json_results = response.read()
+ r_obj = json.loads(json_results)
+ response.close()
+ return r_obj
diff --git a/webapi/youtube.py b/webapi/youtube.py
new file mode 100644
index 0000000..a25f5ba
--- /dev/null
+++ b/webapi/youtube.py
@@ -0,0 +1,61 @@
+from webapi.web_api import WebAPI
+
+
+class YouTubeAPI(WebAPI):
+ """
+ Class for interacting with the YouTube API
+ """
+
+ def __init__(self, api_key: str = None):
+ self.api_key = api_key
+ self.base_url = "https://www.googleapis.com/youtube/v3/"
+
+ def _search_matching_id(self, id: str, data: list) -> dict:
+ """
+ Searches for a info matching a given ID
+ param:
+ id: str - the ID to search for
+ """
+ for entry in data:
+ if entry['id'] == id:
+ return entry
+ return None
+
+ def get_data_all_channels(self, channel_tuples: list) -> list:
+ data = []
+ members = len(channel_tuples)
+ request_chunks = [channel_tuples[i:i + 50] for i in range(0, members, 50)]
+ for chunk in request_chunks:
+ channel_ids = [x[0] for x in chunk]
+ channel_names = [x[1] for x in chunk]
+ request_string = ",".join(channel_ids)
+ stats = self._download_url(
+ f"channels?part=statistics&id={request_string}&key={self.api_key}")
+ snippet = self._download_url(
+ f"channels?part=snippet&id={request_string}&key={self.api_key}")
+ stats_list = stats['items']
+ snippet_list = snippet['items']
+ for i in range(len(stats_list)):
+ try:
+ # group/sub_org is used to further divide channels into subsets (sorta like teams)
+ # can't think of a better match via YouTube API rn other than customUrl
+ data_entry = {'english_name': channel_names[i], 'id': channel_ids[i],
+ 'subscriber_count':
+ self._search_matching_id(channel_ids[i], stats_list)['statistics']['subscriberCount'],
+ 'view_count':
+ self._search_matching_id(channel_ids[i], stats_list)['statistics']['viewCount'],
+ 'photo':
+ self._search_matching_id(channel_ids[i], snippet_list)['snippet']['thumbnails']['default']['url'],
+ 'description':
+ self._search_matching_id(channel_ids[i], snippet_list)['snippet']['description'],
+ 'group':
+ self._search_matching_id(channel_ids[i], snippet_list)['snippet']['customUrl'],
+ 'video_count':
+ self._search_matching_id(channel_ids[i], stats_list)['statistics']['videoCount']
+ }
+ data.append(data_entry)
+ except TypeError:
+ print("Error NoneType: " + str(channel_ids[i]))
+ except KeyError:
+ print("Error KeyError: " + str(channel_ids[i]))
+ return data
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage