-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.py
151 lines (120 loc) · 4.24 KB
/
util.py
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import enum
import json
import sys
from collections import Counter, namedtuple
from enum import Enum
@enum.unique
class ReactionType(Enum):
"""Types of Facebook Messenger reaction emojis.
Arguments:
Enum {string} -- escaped strings and corresponding reaction type
"""
ANGRY = "\u00f0\u009f\u0098\u00a0"
DISLIKE = "\u00f0\u009f\u0091\u008e"
HAHA = "\u00f0\u009f\u0098\u0086"
LIKE = "\u00f0\u009f\u0091\u008d"
LOVE = "\u00f0\u009f\u0098\u008d"
SAD = "\u00f0\u009f\u0098\u00a2"
WOW = "\u00f0\u009f\u0098\u00ae"
@enum.unique
class MessageType(Enum):
"""Type of message.
Arguments:
Enum {int} -- enumerate type of message.
"""
TEXT = enum.auto()
STICKER = enum.auto()
PHOTO = enum.auto()
PLAN = enum.auto()
# Associates a reaction type with the name of the person that reacted
Reaction = namedtuple('Reaction', ['actor', 'reaction_type'])
class Message:
def __init__(self, sender, timestamp_ms, content, reactions, message_type):
self._sender = sender
self._timestamp_ms = timestamp_ms
self._content = content
self._reactions = reactions
self._message_type = message_type
@property
def sender(self):
return self._sender
@property
def timestamp_ms(self):
return self._timestamp_ms
@property
def content(self):
return self._content
@property
def reactions(self):
return self._reactions
@property
def message_type(self):
return self._message_type
@staticmethod
def make_message(raw_message):
# Handle corner case of deactivated / deleted account
sender = raw_message.get("sender_name", "Facebook User")
timestamp_ms = raw_message["timestamp_ms"]
content = raw_message.get("content", "")
reactions = []
for reaction in raw_message.get("reactions", []):
try:
reactions.append(
Reaction(reaction["actor"], ReactionType(reaction["reaction"])))
except ValueError:
# Possible corner case if non-standard reacts are used
continue
# Parse message type
if "plan" in raw_message:
message_type = MessageType.PLAN
elif "photos" in raw_message:
message_type = MessageType.PHOTO
elif "sticker" in raw_message:
message_type = MessageType.STICKER
else:
message_type = MessageType.TEXT
return Message(sender, timestamp_ms, content, reactions, message_type)
class MessageThread:
"""Wraps a `message.json` file generated from the Facebook Messenger
data download, calculating aggregated statistics.
"""
def __init__(self, path):
"""Constructs a MessageThread, calculating read-only attributes.
Arguments:
path {Path} -- path object pointing to a `message.json`
"""
with open(path, 'r') as f:
message_thread = json.load(f)
self._participants = message_thread.get("participants", "Just You")
self._messages = [Message.make_message(raw_message) for
raw_message in message_thread["messages"]]
self._title = message_thread["title"]
@property
def participants(self):
"""Return list of participants in the conversation thread.
Returns:
list[string] -- list of participants
"""
return self._participants
@property
def messages(self):
"""Return list of Message objects from the raw messages.
Returns:
list[Message] -- parsed messages
"""
return self._messages
@property
def title(self):
"""Name of the thread.
Name of the group chat if three or more participants,
name of the other person otherwise.
Returns:
string -- name of the thread
"""
return self._title
def timestamp_range(self):
"""Assumes messages are chronologically ordered."""
return [self._messages[-1].timestamp_ms, self._messages[0].timestamp_ms]
def message_counts(self):
"""Returns map of unique sender to number of messages."""
return Counter(message.sender for message in self._messages)