Browse Source

Added VineUserIE extractor for vine user timeline

Added vine user timeline extractor using unofficial
vine api user profile and timeline api endpoints.
Jason Normore 11 years ago
parent
commit
ea783d01e1
3 changed files with 48 additions and 1 deletions
  1. 8 0
      test/test_playlists.py
  2. 4 1
      youtube_dl/extractor/__init__.py
  3. 36 0
      youtube_dl/extractor/vine.py

+ 8 - 0
test/test_playlists.py

@@ -23,6 +23,7 @@ from youtube_dl.extractor import (
     VimeoUserIE,
     VimeoUserIE,
     VimeoAlbumIE,
     VimeoAlbumIE,
     VimeoGroupsIE,
     VimeoGroupsIE,
+    VineUserIE,
     UstreamChannelIE,
     UstreamChannelIE,
     SoundcloudSetIE,
     SoundcloudSetIE,
     SoundcloudUserIE,
     SoundcloudUserIE,
@@ -102,6 +103,13 @@ class TestPlaylists(unittest.TestCase):
         self.assertEqual(result['title'], 'Rolex Awards for Enterprise')
         self.assertEqual(result['title'], 'Rolex Awards for Enterprise')
         self.assertTrue(len(result['entries']) > 72)
         self.assertTrue(len(result['entries']) > 72)
 
 
+    def test_vine_user(self):
+        dl = FakeYDL()
+        ie = VineUserIE(dl)
+        result = ie.extract('https://vine.co/Visa')
+        self.assertIsPlaylist(result)
+        self.assertTrue(len(result['entries']) >= 50)
+
     def test_ustream_channel(self):
     def test_ustream_channel(self):
         dl = FakeYDL()
         dl = FakeYDL()
         ie = UstreamChannelIE(dl)
         ie = UstreamChannelIE(dl)

+ 4 - 1
youtube_dl/extractor/__init__.py

@@ -305,7 +305,10 @@ from .vimeo import (
     VimeoReviewIE,
     VimeoReviewIE,
     VimeoWatchLaterIE,
     VimeoWatchLaterIE,
 )
 )
-from .vine import VineIE
+from .vine import (
+    VineIE,
+    VineUserIE,
+)
 from .viki import VikiIE
 from .viki import VikiIE
 from .vk import VKIE
 from .vk import VKIE
 from .vube import VubeIE
 from .vube import VubeIE

+ 36 - 0
youtube_dl/extractor/vine.py

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 
 import re
 import re
 import json
 import json
+import itertools
 
 
 from .common import InfoExtractor
 from .common import InfoExtractor
 from ..utils import unified_strdate
 from ..utils import unified_strdate
@@ -58,3 +59,38 @@ class VineIE(InfoExtractor):
             'repost_count': data['reposts']['count'],
             'repost_count': data['reposts']['count'],
             'formats': formats,
             'formats': formats,
         }
         }
+
+class VineUserIE(InfoExtractor):
+    IE_NAME = 'vine:user'
+    _VALID_URL = r'(?:https?://)?vine\.co/(?P<user>[^/]+)/?(\?.*)?$'
+    _VINE_BASE_URL = "https://vine.co/"
+
+    def _profile_url(self, user):
+        return "%sapi/users/profiles/vanity/%s"%(self._VINE_BASE_URL, user)
+
+    def _timeline_url(self, user_id, page=1):
+        return "%sapi/timelines/users/%s?page=%s"%(self._VINE_BASE_URL, user_id, page)
+
+    def _profile_data(self, user):
+        return self._download_json(self._profile_url(user), user)
+
+    def _timeline_data(self, user):
+        profile_data = self._profile_data(user)
+        user_id = profile_data['data']['userId']
+        timeline_data = []
+        for pagenum in itertools.count(1):
+            timeline_page = self._download_json(self._timeline_url(user_id, pagenum), user)
+            timeline_data.extend(timeline_page['data']['records'])
+            if timeline_page['data']['nextPage'] is None:
+                break
+        return timeline_data
+
+    def _extract_videos(self, user):
+        timeline_data = self._timeline_data(user)
+        entries = [self.url_result(e['permalinkUrl'], 'Vine') for e in timeline_data]
+        return self.playlist_result(entries, user)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        user = mobj.group('user')
+        return self._extract_videos(user)