Skip to content

Commit b511db0

Browse files
authored
v0.0.5
2 parents c68fe9e + f605015 commit b511db0

File tree

8 files changed

+321
-139
lines changed

8 files changed

+321
-139
lines changed

my_feed/modules/post.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def __init__(self, post_id, title, created_at, url):
2020
self.media: List[MediaModel] = []
2121
self.description: str = ''
2222

23+
def __repr__(self):
24+
return f'{self.url}'
25+
2326
def add_media(self, media_id, media_url) -> None:
2427
"""
2528
Append a new media to the Post

my_feed/my_feed.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, platform: Platforms, channel_id: str):
5858
self.is_active = True
5959

6060
# The platform update type (reddit, instagram, etc)
61-
self.platform: str = platform.identifier.value
61+
self.platform: PlatformsId = platform.identifier
6262
self.updater = platform.callable # the updater Class
6363

6464
# initialize last update with an old time
@@ -67,39 +67,53 @@ def __init__(self, platform: Platforms, channel_id: str):
6767
self.__temp_last_update = None
6868

6969
# update the data every minutes interval
70-
self.update_interval: int = 1
70+
self.update_interval: int = 5
7171

7272
# how to identify the last update, to not send again the same data
7373
# this value can be a string, slug, int or tuple based on the platform that you are using
74-
self.last_update_id = None
74+
self.__last_update_id = None
7575
# temporally save the last update id
7676
self.__temp_last_update_id = None
7777

7878
# the channel specification, this must match che update requirements in the platform api
7979
self.id: str = channel_id
8080

81+
def __repr__(self):
82+
return f'{self.platform.value}/{self.id}'
83+
8184
@property
8285
def is_time_to_update(self) -> bool:
8386
if datetime.now() - self.last_update > timedelta(minutes=self.update_interval) and self.is_active:
8487
return True
8588
return False
8689

90+
def reset_last_update_id(self):
91+
self.__last_update_id = None
92+
8793
def update(self) -> List[PostModel]:
8894
updater = self.updater() # create the class
89-
out = updater.update(self.id, self.last_update_id)
95+
out = updater.update(self.id, self.__last_update_id)
9096
self.__temp_last_update = datetime.now()
9197

9298
# temporally save the last update id
9399
# after all the operations on the data are done call set_last_update_now()
94100
self.__temp_last_update_id = updater.last_post_id
95101

96102
# if is the first time the last_update_id is none, so dont show any post
97-
if self.last_update_id:
103+
if self.__last_update_id:
98104
return out
99105
else:
100106
return []
101107

102108
def set_last_update_now(self) -> None:
103109
# update the last id, after all the operation on the data is done
104-
self.last_update_id = self.__temp_last_update_id
110+
self.__last_update_id = self.__temp_last_update_id
105111
self.last_update = self.__temp_last_update
112+
113+
def auto_update(self):
114+
"""Auto update the feed, this can be done also manually"""
115+
out = []
116+
if self.is_time_to_update:
117+
out = self.update()
118+
self.set_last_update_now()
119+
return out

my_feed/platforms/instagram.py

Lines changed: 0 additions & 130 deletions
This file was deleted.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
from enum import Enum
2+
from my_feed.modules.post import PostModel
3+
from my_feed.modules.types import PostType
4+
from my_feed.platforms import PlatformInterface, PlatformsId
5+
from my_feed.platforms.instagram.credentials import credentials_manager
6+
from my_feed.platforms.instagram.login import InstagramLogin
7+
8+
9+
class MediaType(Enum):
10+
video = 'video'
11+
image = 'image'
12+
13+
14+
class Instagram(PlatformInterface):
15+
16+
def __init__(self):
17+
super().__init__()
18+
19+
self.api: InstagramLogin
20+
21+
def __repr__(self):
22+
return PlatformsId.INSTAGRAM.value
23+
24+
def _login(self):
25+
user = credentials_manager.credentials[0]
26+
il = InstagramLogin()
27+
self.api = il.login(user.username, user.password, 'configs/{}_creds.json'.format(user.username))
28+
29+
@staticmethod
30+
def get_media_url(media_data):
31+
media = media_data.get('standard_resolution', {})
32+
return media.get('url')
33+
34+
def story(self, user_id, last_update_id) -> [PostModel]:
35+
"""
36+
story can be get only if you are logged in
37+
Load all the stories from the user loaded
38+
:return: InstagramStory list
39+
"""
40+
out = [] # list of all the items in the story
41+
42+
stories = self.api.user_story_feed(user_id)
43+
44+
reels = stories.get('reel')
45+
if not reels:
46+
return []
47+
48+
reels = reels.get('items')
49+
for reel in reels:
50+
51+
post_id = reel.get('pk')
52+
if post_id == last_update_id:
53+
break
54+
55+
post = PostModel(
56+
post_id=post_id,
57+
title='',
58+
created_at=reel.get('taken_at'),
59+
url=reel.get('link')
60+
)
61+
62+
media_type = MediaType(reel.get('type'))
63+
post.type = PostType.VIDEO if media_type == MediaType.video else PostType.IMAGE
64+
media = reel.get('videos' if media_type == MediaType.video else 'images')
65+
post.add_media(media_id=None, media_url=self.get_media_url(media))
66+
67+
out.append(post)
68+
69+
return out
70+
71+
def post(self, user_id, last_update_id) -> [PostModel]:
72+
"""
73+
Get all the post from the user loaded
74+
Store them as a list of InstagramPost obj
75+
:return: PostModel list
76+
"""
77+
out = []
78+
79+
media = self.api.user_feed(user_id)
80+
81+
items = media.get('items')
82+
for item in items:
83+
84+
post_id = item.get('code')
85+
if post_id == last_update_id:
86+
break
87+
88+
# get description of the post
89+
caption = item.get('caption', {})
90+
text = ''
91+
if caption:
92+
text = caption.get('text', '')
93+
94+
post = PostModel(
95+
post_id=post_id,
96+
title=text,
97+
created_at=item.get('created_time'),
98+
url=item.get('link')
99+
)
100+
101+
"""
102+
Check if is a post with multiple elements
103+
- multi element post has media list inside carousel_media
104+
- if not the object media is no encapsulated
105+
"""
106+
carousel = item.get('carousel_media')
107+
media_type = MediaType(item.get('type'))
108+
post.type = PostType.VIDEO if media_type == MediaType.video else PostType.IMAGE
109+
if carousel:
110+
for c in carousel:
111+
media = c.get('videos' if media_type == MediaType.video else 'images')
112+
post.add_media(media_id=None, media_url=self.get_media_url(media))
113+
114+
else:
115+
media = item.get('videos' if media_type == MediaType.video else 'images')
116+
post.add_media(media_id=None, media_url=self.get_media_url(media))
117+
118+
out.append(post)
119+
120+
return out
121+
122+
def update(self, target, last_update_id):
123+
124+
# decouple the last update id
125+
# this cause instagram have 2 feed sources, stories and posts
126+
last_update_id_story = None
127+
last_update_id_post = None
128+
if last_update_id:
129+
last_update_id_story, last_update_id_post = last_update_id
130+
131+
# do login every time
132+
self._login()
133+
134+
# get the data from the api
135+
story_feed = self.story(target, last_update_id_story)
136+
post_feed = self.post(target, last_update_id_post)
137+
138+
# get the post id from the feed
139+
last_update_id_story = self._get_last_post_id(story_feed, last_update_id_story)
140+
last_update_id_post = self._get_last_post_id(post_feed, last_update_id_post)
141+
142+
# the set feed will also revert it
143+
self._set_feed(post_feed + story_feed)
144+
145+
# update the post id
146+
self._last_post_id = (last_update_id_story, last_update_id_post)
147+
return self._feed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import json
2+
3+
file_name = 'configs/instagram_creds.json'
4+
with open(file_name, 'r', encoding='utf8') as f:
5+
file_data = json.loads(f.read())
6+
f.close()
7+
8+
9+
class CredentialsManager:
10+
"""
11+
Load all the Users Credentials in an array
12+
"""
13+
class _UserCredentials:
14+
def __init__(self, username, password):
15+
self.username = username
16+
self.password = password
17+
self.pass_code = None
18+
19+
def __init__(self):
20+
"""
21+
Load the credentials from the json file
22+
Store them ar list of _UserCredentials obj
23+
"""
24+
self.credentials = []
25+
26+
_credentials = file_data.get('creds')
27+
for el in _credentials:
28+
key = list(el.keys())[0]
29+
self.credentials.append(self._UserCredentials(key, el[key]))
30+
31+
32+
credentials_manager = CredentialsManager()

0 commit comments

Comments
 (0)