From 253c3d6110c3ab268eeafd6ba214003d8e58a46b Mon Sep 17 00:00:00 2001 From: Thomas Wade Date: Tue, 21 Apr 2020 04:39:28 +0930 Subject: [PATCH] Parse submissions --- Comment.py | 7 ++- Submission.py | 163 +++++++++++++++++++++++++++++++++++++++++++++----- User.py | 5 +- 3 files changed, 156 insertions(+), 19 deletions(-) diff --git a/Comment.py b/Comment.py index ffcbec8..adc86dc 100644 --- a/Comment.py +++ b/Comment.py @@ -10,9 +10,12 @@ class Comment: A comment on a FurAffinity submission. """ - def __init__(self): + def __init__(self, submission: Submission, id: int): + self.id = id self.author: User.User = None self.timestamp: datetime = None - self.submission: Submission.Submission = None + self.submission: Submission.Submission = submission self.parent: Comment = None self.replies: List[Comment] = None + self.hidden_by_page_owner = None + self.hidden_by_author = None diff --git a/Submission.py b/Submission.py index 6907beb..ddcbefa 100644 --- a/Submission.py +++ b/Submission.py @@ -11,20 +11,22 @@ class Submission: A FurAffinity submission. """ - def __init__(self, id: int): + def __init__(self, api, id: int): + self._api = api self.id: int = id - self.title: str = None - self.author: User.User = None - self.description: str = None - self.tags: List[str] = None - self.timestamp: datetime = None - self.category: str = None - self.theme: str = None - self.species: str = None - self.gender: str = None - self.faves: int = None - self.comments: List[Comment.Comment] = None - self.views: int = None + self._title: str = None + self._author: User.User = None + self._description: str = None + self._tags: List[str] = None + self._timestamp: datetime = None + self._category: str = None + self._subcategory: str = None + self._theme: str = None + self._species: str = None + self._gender: str = None + self._faves: int = None + self._comments: List[Comment.Comment] = None + self._views: int = None @property def url(self): @@ -33,5 +35,138 @@ class Submission: else: return None + @property + def title(self): + if not self._title: + self._get_submission() + + return self._title + + @property + def author(self): + if not self._author: + self._get_submission() + + return self._author + + @property + def description(self): + if not self._description: + self._get_submission() + + return self._description + + @property + def tags(self): + if not self._tags: + self._get_submission() + + return self._tags + + @property + def timestamp(self): + if not self._timestamp: + self._get_submission() + + return self._timestamp + + @property + def category(self): + if not self._category: + self._get_submission() + + return self._category + + @property + def subcategory(self): + if not self._subcategory: + self._get_submission() + + return self._subcategory + + @property + def species(self): + if not self._species: + self._get_submission() + + return self._species + + @property + def gender(self): + if not self._gender: + self._get_submission() + + return self._gender + + @property + def faves(self): + if not self._faves: + self._get_submission() + + return self._faves + + @property + def comments(self): + if not self._comments: + self._get_submission() + + return self._comments + + @property + def views(self): + if not self._views: + self._get_submission() + + return self._views + + def _get_submission(self): + soup = self._api.get_soup('{}/view/{}'.format(FAAPI.FA_BASE_URL, self.id)) + + # Parse all the easy stuff + self._title = soup.select('.submission-title')[0].text.strip() + self._author = User.User.new_or_cached(self._api, soup.select('.submission-id-sub-container a')[0].text.strip()) + self._description = soup.select('.submission-description')[0].text.strip() + self._tags = [tag.text.strip() for tag in soup.select('.submission-sidebar .tags')] + self._timestamp = datetime.datetime.strptime(soup.select('.popup_date')[0].get('title'), '%b %d, %Y %H:%M %p') # e.g. Nov 26, 2019 02:47 PM + self._category = soup.select('.category-name')[0].text.strip() + self._subcategory = soup.select('.type-name')[0].text.strip() + self._species = soup.select('.info div:nth-of-type(2) span')[0].text.strip() + self._gender = soup.select('.info div:nth-of-type(3) span')[0].text.strip() + self._faves = int(soup.select('.favorites .font-large')[0].text.strip()) + self._views = int(soup.select('.views .font-large')[0].text.strip()) + + # Parse comments + self._comments = [] + for comment_element in soup.select('.comment_container'): + # Parse all the easy stuff + comment = Comment.Comment(self, int(comment_element.select('.comment_anchor')[0].get('id')[4:])) # Skip the 'cid:' in the ID e.g. cid:142785397 + + # TODO: Comment ancestry + + # Toggle hidden status + if comment_element.select('.comment-deleted'): + # Deleted by its owner, set flags and skip remaining attributes + comment.hidden_by_author = True + comment.hidden_by_page_owner = False + + self._comments.append(comment) + continue + elif 'collapsed_height' in comment_element.get('class'): + # Deleted by the page owner, set flags and skip remaining attributes + comment.hidden_by_author = False + comment.hidden_by_page_owner = True + + self._comments.append(comment) + continue + else: + comment.hidden_by_author = False + comment.hidden_by_page_owner = False + + # Parse content from non-hidden comments + comment.author = User.User.new_or_cached(self._api, comment_element.select('.comment_username')[0].text.strip()) + comment.timestamp = datetime.datetime.fromtimestamp(int(comment_element.get('data-timestamp'))) # FIXME: Needs to account for timezone difference since these are server-local epochs. Seems to be hosted in New York's TZ + + self._comments.append(comment) + def __str__(self): - return '{} - {} ({}/view/{})'.format(self.author, self.title, FAAPI.FA_BASE_URL, self.id) + return '{} - {} ({}/view/{})'.format(self.author, self.title, self.url) diff --git a/User.py b/User.py index 1a6f361..5f0fc23 100644 --- a/User.py +++ b/User.py @@ -78,8 +78,7 @@ class User: # Get all the submissions on this page for item in soup.select('.gallery figure'): - sub = Submission.Submission(item.get('id')[4:]) # IDs look like 'sid-35908275', so we just skip the 'sid-' - sub.author = self + sub = Submission.Submission(self._api, int(item.get('id')[4:])) # IDs look like 'sid-35908275', so we just skip the 'sid-' submissions.append(sub) return submissions @@ -100,7 +99,7 @@ class User: # Get all the submissions on this page for item in soup.select('.gallery figure'): - sub = Submission.Submission(item.get('id')[4:]) # IDs look like 'sid-35908275', so we just skip the 'sid-' + sub = Submission.Submission(self._api, int(item.get('id')[4:])) # IDs look like 'sid-35908275', so we just skip the 'sid-' submissions.append(sub) return submissions