Repository: line/line-bot-sdk-python
Pull request #177 (2019-06-14 10:23:55)

New fields (mainly, contentProvider) in Image, Video, and Audio
#131 

1. New fields
    - **content_provider** in Image, Video, and Audio
    - **duraton** in Video, and Audio
1. Add tests
    - for new properties, **content_provider** and **duraton**
1. Fix reference URL in pydoc


Patch:
diff --git a/linebot/models/messages.py b/linebot/models/messages.py
index ace6e23..f541d29 100644
--- a/linebot/models/messages.py
+++ b/linebot/models/messages.py
@@ -41,7 +41,7 @@ class Message(with_metaclass(ABCMeta, Base)):
 class TextMessage(Message):
     """TextMessage.
 
-    https://devdocs.line.me/en/#text-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-text
 
     Message object which contains the text sent from the source.
     """
@@ -62,67 +62,89 @@ class TextMessage(Message):
 class ImageMessage(Message):
     """ImageMessage.
 
-    https://devdocs.line.me/en/#image-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-image
 
     Message object which contains the image content sent from the source.
     The binary image data can be retrieved with the Content API.
     """
 
-    def __init__(self, id=None, **kwargs):
+    def __init__(self, id=None, content_provider=None, **kwargs):
         """__init__ method.
 
         :param str id: Message ID
+        :param content_provider: ContentProvider object
+        :type content_provider:
+            :py:class:`linebot.models.messages.ContentProvider` | dict[str, str]
         :param kwargs:
         """
         super(ImageMessage, self).__init__(id=id, **kwargs)
 
         self.type = 'image'
+        self.content_provider = self.get_or_new_from_json_dict(
+            content_provider, ContentProvider
+        )
 
 
 class VideoMessage(Message):
     """VideoMessage.
 
-    https://devdocs.line.me/en/#video-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-video
 
     Message object which contains the video content sent from the source.
     The binary video data can be retrieved with the Content API.
     """
 
-    def __init__(self, id=None, **kwargs):
+    def __init__(self, id=None, duration=None, content_provider=None, **kwargs):
         """__init__ method.
 
         :param str id: Message ID
+        :param long duration: Length of video file (milliseconds)
+        :param content_provider: ContentProvider object
+        :type content_provider:
+            :py:class:`linebot.models.messages.ContentProvider` | dict[str, str]
         :param kwargs:
         """
         super(VideoMessage, self).__init__(id=id, **kwargs)
 
         self.type = 'video'
+        self.duration = duration
+        self.content_provider = self.get_or_new_from_json_dict(
+            content_provider, ContentProvider
+        )
 
 
 class AudioMessage(Message):
     """AudioMessage.
 
-    https://devdocs.line.me/en/#audio-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-audio
 
     Message object which contains the audio content sent from the source.
     The binary audio data can be retrieved with the Content API.
     """
 
-    def __init__(self, id=None, **kwargs):
+    def __init__(self, id=None, duration=None, content_provider=None, **kwargs):
         """__init__ method.
 
         :param str id: Message ID
+        :param long duration: Length of audio file (milliseconds)
+        :param content_provider: ContentProvider object
+        :type content_provider:
+            :py:class:`linebot.models.messages.ContentProvider` | dict[str, str]
         :param kwargs:
         """
         super(AudioMessage, self).__init__(id=id, **kwargs)
 
         self.type = 'audio'
+        self.duration = duration
+        self.content_provider = self.get_or_new_from_json_dict(
+            content_provider, ContentProvider
+        )
 
 
 class LocationMessage(Message):
     """LocationMessage.
 
-    https://devdocs.line.me/en/#location-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-location
     """
 
     def __init__(self, id=None, title=None, address=None, latitude=None, longitude=None,
@@ -148,7 +170,7 @@ class LocationMessage(Message):
 class StickerMessage(Message):
     """StickerMessage.
 
-    https://devdocs.line.me/en/#sticker-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-sticker
 
     Message object which contains the sticker data sent from the source.
     For a list of basic LINE stickers and sticker IDs, see sticker list.
@@ -172,7 +194,7 @@ class StickerMessage(Message):
 class FileMessage(Message):
     """FileMessage.
 
-    https://devdocs.line.me/en/#file-message
+    https://developers.line.biz/en/reference/messaging-api/#wh-file
 
     Message object which contains the file content sent from the source.
     The binary file data can be retrieved with the Content API.
@@ -191,3 +213,21 @@ class FileMessage(Message):
         self.type = 'file'
         self.file_size = file_size
         self.file_name = file_name
+
+
+class ContentProvider(Base):
+    """Content provider."""
+
+    def __init__(self, type=None, original_content_url=None, preview_image_url=None, **kwargs):
+        """__init__ method.
+
+        :param str type: Provider of the content. `line` or `external`.
+        :param str original_content_url: URL of the content.
+        :param str preview_image_url: URL of the preview image.
+        :param kwargs:
+        """
+        super(ContentProvider, self).__init__(**kwargs)
+
+        self.type = type
+        self.original_content_url = original_content_url
+        self.preview_image_url = preview_image_url


Test patch:
diff --git a/tests/test_webhook.py b/tests/test_webhook.py
index a6e3b5f..8f6b0e7 100644
--- a/tests/test_webhook.py
+++ b/tests/test_webhook.py
@@ -87,6 +87,11 @@ class TestWebhookParser(unittest.TestCase):
         self.assertIsInstance(events[1].message, ImageMessage)
         self.assertEqual(events[1].message.id, '325708')
         self.assertEqual(events[1].message.type, 'image')
+        self.assertEqual(events[1].message.content_provider.type, 'external')
+        self.assertEqual(events[1].message.content_provider.original_content_url,
+                         "https://example.com")
+        self.assertEqual(events[1].message.content_provider.preview_image_url,
+                         "https://example.com")
 
         # MessageEvent, SourceUser, VideoMessage
         self.assertIsInstance(events[2], MessageEvent)
@@ -100,6 +105,12 @@ class TestWebhookParser(unittest.TestCase):
         self.assertIsInstance(events[2].message, VideoMessage)
         self.assertEqual(events[2].message.id, '325708')
         self.assertEqual(events[2].message.type, 'video')
+        self.assertEqual(events[2].message.duration, 60000)
+        self.assertEqual(events[2].message.content_provider.type, 'external')
+        self.assertEqual(events[2].message.content_provider.original_content_url,
+                         "https://example.com")
+        self.assertEqual(events[2].message.content_provider.preview_image_url,
+                         "https://example.com")
 
         # MessageEvent, SourceUser, AudioMessage
         self.assertIsInstance(events[3], MessageEvent)
@@ -113,6 +124,10 @@ class TestWebhookParser(unittest.TestCase):
         self.assertIsInstance(events[3].message, AudioMessage)
         self.assertEqual(events[3].message.id, '325708')
         self.assertEqual(events[3].message.type, 'audio')
+        self.assertEqual(events[3].message.duration, 60000)
+        self.assertEqual(events[3].message.content_provider.type, 'external')
+        self.assertEqual(events[3].message.content_provider.original_content_url,
+                         "https://example.com")
 
         # MessageEvent, SourceUser, LocationMessage
         self.assertIsInstance(events[4], MessageEvent)
diff --git a/tests/text/webhook.json b/tests/text/webhook.json
index bfa54ec..d52eb30 100644
--- a/tests/text/webhook.json
+++ b/tests/text/webhook.json
@@ -24,7 +24,12 @@
       },
       "message": {
         "id": "325708",
-        "type": "image"
+        "type": "image",
+        "contentProvider": {
+          "type": "external",
+          "originalContentUrl": "https://example.com",
+          "previewImageUrl": "https://example.com"
+        }
       }
     },
     {
@@ -37,7 +42,13 @@
       },
       "message": {
         "id": "325708",
-        "type": "video"
+        "type": "video",
+        "duration": 60000,
+        "contentProvider": {
+          "type": "external",
+          "originalContentUrl": "https://example.com",
+          "previewImageUrl": "https://example.com"
+        }
       }
     },
     {
@@ -50,7 +61,12 @@
       },
       "message": {
         "id": "325708",
-        "type": "audio"
+        "type": "audio",
+        "duration": 60000,
+        "contentProvider": {
+          "type": "external",
+          "originalContentUrl": "https://example.com"
+        }
       }
     },
     {