Procházet zdrojové kódy

Add support for Instagram->Matrix location messages

Tulir Asokan před 4 roky
rodič
revize
aa75c2a2be

+ 1 - 1
ROADMAP.md

@@ -22,7 +22,7 @@
       * [x] Videos
       * [x] Gifs
       * [x] Voice messages
-      * [ ] Locations
+      * [x] Locations
   * [x] Message unsend
   * [x] Message reactions
   * [x] Message history

+ 2 - 1
mauigpapi/types/__init__.py

@@ -12,7 +12,8 @@ from .thread_item import (ThreadItemType, ThreadItemActionLog, ViewMode, Creativ
                           CreateModeAttribution, ImageVersion, ImageVersions, VisualMedia, Caption,
                           RegularMediaItem, MediaShareItem, ReplayableMediaItem, VideoVersion,
                           AudioInfo, VoiceMediaItem, AnimatedMediaImage, AnimatedMediaImages,
-                          AnimatedMediaItem, ThreadItem, VoiceMediaData, Reaction, Reactions)
+                          AnimatedMediaItem, ThreadItem, VoiceMediaData, Reaction, Reactions,
+                          Location)
 from .thread import Thread, ThreadUser, ThreadItem, ThreadUserLastSeenAt, ThreadTheme
 from .mqtt import (Operation, ThreadAction, ReactionStatus, TypingStatus, CommandResponsePayload,
                    CommandResponse, IrisPayloadData, IrisPayload, MessageSyncMessage,

+ 15 - 0
mauigpapi/types/thread_item.py

@@ -290,6 +290,20 @@ class Reactions(SerializableAttrs['Reactions']):
     emojis: List[Reaction] = attr.ib(factory=lambda: [])
 
 
+@dataclass
+class Location(SerializableAttrs['Location']):
+    pk: int
+    short_name: str
+    facebook_places_id: int
+    # TODO enum?
+    external_source: str  # facebook_places
+    name: str
+    address: str
+    city: str
+    lng: float
+    lat: float
+
+
 @dataclass(kw_only=True)
 class ThreadItem(SerializableAttrs['ThreadItem']):
     item_id: Optional[str] = None
@@ -308,4 +322,5 @@ class ThreadItem(SerializableAttrs['ThreadItem']):
     animated_media: Optional[AnimatedMediaItem] = None
     visual_media: Optional[VisualMedia] = None
     media_share: Optional[MediaShareItem] = None
+    location: Optional[Location] = None
     reactions: Optional[Reactions] = None

+ 25 - 2
mautrix_instagram/portal.py

@@ -24,12 +24,12 @@ import magic
 
 from mauigpapi.types import (Thread, ThreadUser, ThreadItem, RegularMediaItem, MediaType,
                              ReactionStatus, Reaction, AnimatedMediaItem, ThreadItemType,
-                             VoiceMediaItem)
+                             VoiceMediaItem, Location)
 from mautrix.appservice import AppService, IntentAPI
 from mautrix.bridge import BasePortal, NotificationDisabler
 from mautrix.types import (EventID, MessageEventContent, RoomID, EventType, MessageType, ImageInfo,
                            VideoInfo, MediaMessageEventContent, TextMessageEventContent, AudioInfo,
-                           ContentURI, EncryptedFile)
+                           ContentURI, EncryptedFile, LocationMessageEventContent, Format)
 from mautrix.errors import MatrixError, MForbidden
 from mautrix.util.simple_lock import SimpleLock
 from mautrix.util.network_retry import call_with_net_retry
@@ -334,6 +334,27 @@ class Portal(DBPortal, BasePortal):
         content = TextMessageEventContent(msgtype=MessageType.TEXT, body=item.text)
         return await self._send_message(intent, content, timestamp=item.timestamp // 1000)
 
+    async def _handle_instagram_location(self, intent: IntentAPI, item: ThreadItem) -> EventID:
+        loc = item.location
+        long_char = "E" if loc.lng > 0 else "W"
+        lat_char = "N" if loc.lat > 0 else "S"
+
+        body = (f"{loc.name} - {round(abs(loc.lat), 4)}° {lat_char}, "
+                f"{round(abs(loc.lng), 4)}° {long_char}")
+        url = f"https://www.openstreetmap.org/#map=15/{loc.lat}/{loc.lng}"
+
+        external_url = None
+        if loc.external_source == "facebook_places":
+            external_url = f"https://www.facebook.com/{loc.short_name}-{loc.facebook_places_id}"
+
+        content = LocationMessageEventContent(
+            msgtype=MessageType.LOCATION, geo_uri=f"geo:{loc.lat},{loc.lng}",
+            body=f"Location: {body}\n{url}", external_url=external_url)
+        content["format"] = str(Format.HTML)
+        content["formatted_body"] = f"Location: <a href='{url}'>{body}</a>"
+
+        return await self._send_message(intent, content, timestamp=item.timestamp // 1000)
+
     async def handle_instagram_item(self, source: 'u.User', sender: 'p.Puppet', item: ThreadItem,
                                     is_backfill: bool = False) -> None:
         if item.client_context in self._reqid_dedup:
@@ -359,6 +380,8 @@ class Portal(DBPortal, BasePortal):
             event_id = None
             if item.media or item.animated_media or item.voice_media:
                 event_id = await self._handle_instagram_media(source, intent, item)
+            elif item.location:
+                event_id = await self._handle_instagram_location(intent, item)
             if item.text:
                 event_id = await self._handle_instagram_text(intent, item)
             # TODO handle other attachments