├── README.md ├── instagram1.png ├── README.txt └── client.py /README.md: -------------------------------------------------------------------------------- 1 | Tarea3lp 2 | ======== 3 | -------------------------------------------------------------------------------- /instagram1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gonzalezf/Tarea3lp/master/instagram1.png -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | =============Integrantes============= 2 | 3 | -Felipe Morales (201273564-5) 4 | -Felipe Gonzalez (201273533-0) 5 | 6 | ================Notas============== 7 | -Se ejecuta usando ./client.py 8 | -Se utilizo la libería PIL para mostrar las imágenes en JPG -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import re 5 | import urllib 6 | import urllib2 7 | from Tkinter import * 8 | import Tkinter as tk 9 | from ttk import Frame, Button, Style 10 | import os 11 | from PIL import Image, ImageTk 12 | 13 | #Nuestro token global... por ahora lo obtendremos asi... 14 | #token = "1320147380.b4a3796.86fc6de63606444e9e34e795a6793606" 15 | client_id = "b4a37965871b48f79e5365fa097f8e24" 16 | 17 | OUR_PROFILE_ID = "1320147380" 18 | 19 | #usado para cambiar el tamaño de todas las cosas 20 | radio = 1.5 21 | 22 | #Ventana principal, la idea es tener un sidebar a la izquierda que se mantenga 23 | #igual, y solo variar el contenido de adentro. 24 | class MainWindow(Frame): 25 | current_post = 0 26 | #Esta es la ventana que contiene a todo, es similar al a tarea anterior 27 | #Constructor 28 | """******** Funcion: __init__ ************** 29 | Descripcion: Constructor de nuestra ventana 30 | Parametros: 31 | master = Ventana tkinter opcional 32 | Retorno: Sin retorno 33 | *****************************************************""" 34 | def __init__(self, master=None): 35 | #Inicializamos el frame 36 | Frame.__init__(self, master) 37 | 38 | #Dejamos la ventana Tk como maestra o root 39 | self.master = master 40 | self.token = 'invalid' 41 | 42 | #Diseñamos un canvas en el cual podemos insertar o remover elementos 43 | #Es como una especie de panel al que se le agregan distintos elementos 44 | self.canvas = Canvas(width = int(700*radio), height = int(400*radio)) 45 | 46 | #Lista de objetos en el canvas (para poder borrarlos) 47 | #Esta lista no incluye los elementos del sidebar!! 48 | self.objects = [] 49 | self.view_profile = {} 50 | self.profile = {} 51 | self.feed = {} 52 | self.following = {} 53 | self.followers = {} 54 | self.search_reply = {} 55 | 56 | #Dibujar! 57 | self.Initialize() 58 | 59 | 60 | """******** Funcion: OnFollowButton ************** 61 | Descripcion: Funcion llamada cuando se hace click en el 62 | boton para seguir o dejar de seguir (segun contexto) 63 | Parametros: 64 | profile perfil a recargar 65 | Retorno: Sin retorno 66 | *****************************************************""" 67 | def OnFollowButton(self, profile): 68 | action = "" 69 | if(self.view_profile['is_followed'] == 'none'): 70 | action = "follow" 71 | else: 72 | action = "unfollow" 73 | request = "https://api.instagram.com/v1/users/"+profile+"/relationship" 74 | data = urllib.urlencode({"action": action, "access_token": self.token}) 75 | response = urllib.urlopen(request, data) 76 | the_page = response.read() 77 | self.DrawOtherProfile(profile, 1) 78 | 79 | 80 | """******** Funcion: ParseSearch ************** 81 | Descripcion: Realiza llamada a API de instagram y parsea 82 | la respuesta con expresiones regulares 83 | Parametros: 84 | name Nombre a buscar 85 | Retorno: Sin retorno 86 | *****************************************************""" 87 | def ParseSearch(self, name): 88 | request = "https://api.instagram.com/v1/users/search?q="+name+"&access_token="+self.token 89 | print request 90 | response = urllib2.urlopen(request) 91 | the_page = response.read() 92 | 93 | self.search_reply['pictures'] = [] 94 | self.search_reply['ids'] = [] 95 | self.search_reply['names'] = [] 96 | matchImage = re.findall(r'"profile_picture"[^,}]*', the_page) 97 | matchId = re.findall(r'"id"[^,}]*', the_page) 98 | matchName = re.findall(r'"username"[^,}]*', the_page) 99 | self.search_reply['pictures'].append('NULL') 100 | self.search_reply['ids'].append('NULL') 101 | self.search_reply['names'].append('NULL') 102 | if len(matchImage) > 0: 103 | for x in xrange(0,len(matchImage)): 104 | image = matchImage[x].replace('\\','').split(':', 1)[1][1:-1] 105 | 106 | #Descargo la imagen 107 | s = image.split('/') 108 | image_file = s[len(s)-1] 109 | 110 | if not os.path.exists("img"): 111 | os.makedirs("img") 112 | if(not os.path.isfile("img/"+image_file)): 113 | urllib.urlretrieve(image, "img/"+image_file) 114 | self.search_reply['pictures'].append(image_file) 115 | print image_file 116 | self.search_reply['ids'].append(matchId[x].split(':', 1)[1][1:-1].replace('\\','')) 117 | self.search_reply['names'].append(matchName[x].split(':', 1)[1][1:-1].replace('\\','')) 118 | print matchId[x].split(':', 1)[1][1:-1].replace('\\','') 119 | 120 | 121 | 122 | """******** Funcion: ParseFollowers ************** 123 | Descripcion: Realiza llamada a API de instagram y parsea 124 | la respuesta con expresiones regulares 125 | Retorno: Sin retorno 126 | *****************************************************""" 127 | def ParseFollowers(self): 128 | request = "https://api.instagram.com/v1/users/"+OUR_PROFILE_ID+"/followed-by?access_token="+self.token 129 | response = urllib2.urlopen(request) 130 | the_page = response.read() 131 | 132 | 133 | self.followers['pictures'] = [] 134 | self.followers['ids'] = [] 135 | matchImage = re.findall(r'"profile_picture"[^,}]*', the_page) 136 | matchId = re.findall(r'"id"[^,}]*', the_page) 137 | self.followers['pictures'].append('NULL') 138 | self.followers['ids'].append('NULL') 139 | if len(matchImage) > 0: 140 | for x in xrange(0,len(matchImage)): 141 | image = matchImage[x].replace('\\','').split(':', 1)[1][1:-1] 142 | 143 | #Descargo la imagen 144 | s = image.split('/') 145 | image_file = s[len(s)-1] 146 | 147 | if not os.path.exists("img"): 148 | os.makedirs("img") 149 | if(not os.path.isfile("img/"+image_file)): 150 | urllib.urlretrieve(image, "img/"+image_file) 151 | self.followers['pictures'].append(image_file) 152 | print image_file 153 | self.followers['ids'].append(matchId[x].split(':', 1)[1][1:-1].replace('\\','')) 154 | print matchId[x].split(':', 1)[1][1:-1].replace('\\','') 155 | 156 | 157 | """******** Funcion: ParseFollowing ************** 158 | Descripcion: Realiza llamada a API de instagram y parsea 159 | la respuesta con expresiones regulares 160 | Retorno: Sin retorno 161 | *****************************************************""" 162 | def ParseFollowing(self): 163 | request = "https://api.instagram.com/v1/users/"+OUR_PROFILE_ID+"/follows?access_token="+self.token 164 | response = urllib2.urlopen(request) 165 | the_page = response.read() 166 | 167 | 168 | self.following['pictures'] = [] 169 | self.following['ids'] = [] 170 | matchImage = re.findall(r'"profile_picture"[^,}]*', the_page) 171 | matchId = re.findall(r'"id"[^,}]*', the_page) 172 | self.following['pictures'].append('NULL') 173 | self.following['ids'].append('NULL') 174 | if len(matchImage) > 0: 175 | for x in xrange(0,len(matchImage)): 176 | image = matchImage[x].replace('\\','').replace('\\','').split(':', 1)[1][1:-1] 177 | 178 | #Descargo la imagen 179 | s = image.split('/') 180 | image_file = s[len(s)-1] 181 | 182 | if not os.path.exists("img"): 183 | os.makedirs("img") 184 | if(not os.path.isfile("img/"+image_file)): 185 | urllib.urlretrieve(image, "img/"+image_file) 186 | 187 | 188 | 189 | self.following['pictures'].append(image_file) 190 | print image_file 191 | self.following['ids'].append(matchId[x].split(':', 1)[1][1:-1].replace('\\','')) 192 | print matchId[x].split(':', 1)[1][1:-1].replace('\\','') 193 | 194 | 195 | 196 | """******** Funcion: ParseProfile ************** 197 | Descripcion: Realiza llamada a API de instagram y parsea 198 | la respuesta con expresiones regulares 199 | Retorno: Sin retorno 200 | *****************************************************""" 201 | def ParseProfile(self): 202 | request = "https://api.instagram.com/v1/users/"+OUR_PROFILE_ID+"?access_token="+self.token 203 | response = urllib2.urlopen(request) 204 | the_page = response.read() 205 | 206 | #Leer el jason oe sixd 207 | matchUser = re.search(r'"username":[^\n,}]*', the_page) 208 | matchBio = re.search(r'"bio":[^\n,}]*', the_page) 209 | matchWebsite = re.search(r'"website":[^\n,}]*', the_page) 210 | matchPicture = re.search(r'"profile_picture":[^\n,}]*', the_page) 211 | matchName = re.search(r'"full_name":[^\n,}]*', the_page) 212 | matchMedia = re.search(r'"media":[^\n,}]*', the_page) 213 | matchFollowedBy = re.search(r'"followed_by":[^\n,}]*', the_page) 214 | matchFollows = re.search(r'"follows":[^\n,}]*', the_page) 215 | self.profile['username'] = matchUser.group(0).split(':', 1)[1][1:-1].replace('\\','') 216 | self.profile['bio'] = matchBio.group(0).split(':', 1)[1][1:-1].replace('\\','') 217 | self.profile['website'] = matchWebsite.group(0).split(':', 1)[1][1:-1].replace('\\','') 218 | self.profile['picture'] = matchPicture.group(0).split(':', 1)[1][1:-1].replace('\\','') 219 | s = self.profile['picture'].split('/') 220 | image_file = s[len(s)-1] 221 | 222 | if not os.path.exists("img"): 223 | os.makedirs("img") 224 | if(not os.path.isfile("img/"+image_file)): 225 | urllib.urlretrieve(self.profile['picture'], "img/"+image_file) 226 | self.profile['picture'] = image_file 227 | 228 | 229 | self.profile['name'] = matchName.group(0).split(':', 1)[1][1:-1].replace('\\','') 230 | self.profile['media'] = matchMedia.group(0).split(':', 1)[1] 231 | self.profile['followed_by'] = matchFollowedBy.group(0).split(':', 1)[1] 232 | self.profile['follows'] = matchFollows.group(0).split(':', 1)[1] 233 | 234 | """******** Funcion: ParseOtherProfile ************** 235 | Descripcion: Realiza llamada a API de instagram y parsea 236 | la respuesta con expresiones regulares 237 | Parametros: 238 | profile perfil a buscar y parsear 239 | Retorno: Sin retorno 240 | *****************************************************""" 241 | def ParseOtherProfile(self, profile): 242 | request = "https://api.instagram.com/v1/users/"+profile+"?access_token="+self.token 243 | response = urllib2.urlopen(request) 244 | the_page = response.read() 245 | 246 | #Leer el jason oe sixd 247 | matchUser = re.search(r'"username":[^\n,}]*', the_page) 248 | matchBio = re.search(r'"bio":[^\n,}]*', the_page) 249 | matchWebsite = re.search(r'"website":[^\n,}]*', the_page) 250 | matchPicture = re.search(r'"profile_picture":[^\n,}]*', the_page) 251 | matchName = re.search(r'"full_name":[^\n,}]*', the_page) 252 | matchMedia = re.search(r'"media":[^\n,}]*', the_page) 253 | matchFollowedBy = re.search(r'"followed_by":[^\n,}]*', the_page) 254 | matchFollows = re.search(r'"follows":[^\n,}]*', the_page) 255 | self.view_profile['profile_id'] = profile 256 | self.view_profile['username'] = matchUser.group(0).split(':', 1)[1][1:-1].replace('\\','') 257 | self.view_profile['bio'] = matchBio.group(0).split(':', 1)[1][1:-1].replace('\\','') 258 | self.view_profile['website'] = matchWebsite.group(0).split(':', 1)[1][1:-1].replace('\\','') 259 | self.view_profile['picture'] = matchPicture.group(0).split(':', 1)[1][1:-1].replace('\\','') 260 | s = self.view_profile['picture'].split('/') 261 | image_file = s[len(s)-1] 262 | 263 | if not os.path.exists("img"): 264 | os.makedirs("img") 265 | if(not os.path.isfile("img/"+image_file)): 266 | urllib.urlretrieve(self.view_profile['picture'], "img/"+image_file) 267 | self.view_profile['picture'] = image_file 268 | 269 | self.view_profile['name'] = matchName.group(0).split(':', 1)[1][1:-1].replace('\\','') 270 | self.view_profile['media'] = matchMedia.group(0).split(':', 1)[1] 271 | self.view_profile['followed_by'] = matchFollowedBy.group(0).split(':', 1)[1] 272 | self.view_profile['follows'] = matchFollows.group(0).split(':', 1)[1] 273 | request = "https://api.instagram.com/v1/users/"+profile+"/relationship?access_token="+self.token 274 | response = urllib2.urlopen(request) 275 | the_page = response.read() 276 | 277 | matchRelationship = re.search(r'"outgoing_status":[^\n,}]*', the_page) 278 | self.view_profile['is_followed'] = matchRelationship.group(0).split(':', 1)[1][1:-1].replace('\\','') 279 | 280 | 281 | """******** Funcion: ParseOwnRecentPhotos ************** 282 | Descripcion: Realiza llamada a API de instagram y parsea 283 | la respuesta con expresiones regulares 284 | Retorno: Sin retorno 285 | *****************************************************""" 286 | def ParseOwnRecentPhotos(self): 287 | request = "https://api.instagram.com/v1/users/"+OUR_PROFILE_ID+"/media/recent?access_token="+self.token 288 | response = urllib2.urlopen(request) 289 | the_page = response.read() 290 | 291 | #Guardaremos aqui las cosas 292 | self.view_profile['images'] = [] 293 | matchImage = re.findall(r'"standard_resolution":{"url":"(.*?)"', the_page) 294 | 295 | #Buscar videos y eliminarlos de la lista 296 | delete_list = [] 297 | if len(matchImage) > 0: 298 | for x in xrange(0, len(matchImage)): 299 | image = matchImage[x].replace('\\','') 300 | s2 = image.split('.') 301 | print s2[len(s2)-1] 302 | if(s2[len(s2)-1] == "mp4"): 303 | delete_list.append(x) 304 | removed = 0 305 | for d in delete_list: 306 | print "Removing: "+str(d-removed) 307 | del matchImage[d-removed] 308 | removed+=1 309 | #Comenzar a obtener la informacion 310 | self.view_profile['images'].append('NULL') 311 | if len(matchImage) > 0: 312 | for x in xrange(0,len(matchImage)): 313 | image = matchImage[x].replace('\\','') 314 | 315 | #Descargo la imagen 316 | s = image.split('/') 317 | image_file = s[len(s)-1] 318 | 319 | if not os.path.exists("img"): 320 | os.makedirs("img") 321 | if(not os.path.isfile("img/"+image_file)): 322 | urllib.urlretrieve(image, "img/"+image_file) 323 | 324 | 325 | self.view_profile['images'].append(image_file) 326 | 327 | """******** Funcion: ParseFollowers ************** 328 | Descripcion: Realiza llamada a API de instagram y parsea 329 | la respuesta con expresiones regulares 330 | Parametros: 331 | profile perfil a buscar y parsear 332 | Retorno: Sin retorno 333 | *****************************************************""" 334 | def ParseOtherRecentPhotos(self, profile): 335 | request = "https://api.instagram.com/v1/users/"+profile+"/media/recent?access_token="+self.token 336 | response = urllib2.urlopen(request) 337 | the_page = response.read() 338 | #Guardaremos aqui las cosas 339 | self.view_profile['images'] = [] 340 | matchImage = re.findall(r'"standard_resolution":{"url":"(.*?)"', the_page) 341 | 342 | #Buscar videos y eliminarlos de la lista 343 | delete_list = [] 344 | if len(matchImage) > 0: 345 | for x in xrange(0, len(matchImage)): 346 | image = matchImage[x].replace('\\','') 347 | s2 = image.split('.') 348 | print s2[len(s2)-1] 349 | if(s2[len(s2)-1] == "mp4"): 350 | delete_list.append(x) 351 | removed = 0 352 | for d in delete_list: 353 | print "Removing: "+str(d-removed) 354 | del matchImage[d-removed] 355 | removed+=1 356 | #Comenzar a obtener la informacion 357 | self.view_profile['images'].append('NULL') 358 | if len(matchImage) > 0: 359 | for x in xrange(0,len(matchImage)): 360 | image = matchImage[x].replace('\\','') 361 | 362 | #Descargo la imagen 363 | s = image.split('/') 364 | image_file = s[len(s)-1] 365 | 366 | if not os.path.exists("img"): 367 | os.makedirs("img") 368 | if(not os.path.isfile("img/"+image_file)): 369 | urllib.urlretrieve(image, "img/"+image_file) 370 | 371 | 372 | self.view_profile['images'].append(image_file) 373 | 374 | 375 | 376 | #Para expresiones regulares esta pagina es muy buena! 377 | #http://regexpal.com/ 378 | """******** Funcion: ParseFeed ************** 379 | Descripcion: Realiza llamada a API de instagram y parsea 380 | la respuesta con expresiones regulares 381 | Retorno: Sin retorno 382 | *****************************************************""" 383 | def ParseFeed(self): 384 | #Con esto obtenemos la respuesta de instagram 385 | #query = "https://api.instagram.com/v1/users/"+OUR_PROFILE_ID+"/media/recent?access_token="+token 386 | request = "https://api.instagram.com/v1/users/self/feed?access_token="+self.token 387 | response = urllib2.urlopen(request) 388 | the_page = response.read() 389 | self.feed = {} 390 | 391 | #Guardaremos aqui las cosas 392 | self.feed['images'] = [] 393 | self.feed['captions'] = [] 394 | self.feed['comments'] = [] 395 | self.feed['image_file'] = [] 396 | self.feed['userid'] = [] 397 | self.feed['username'] = [] 398 | matchImage = re.findall(r'"standard_resolution":{"url":"(.*?)"', the_page) 399 | matchCaption = re.findall(r'"caption":(.*?),(.*?),', the_page) 400 | matchComment = re.findall(r'"comments":(.*?)\]}', the_page) 401 | matchUser1 = re.findall(r'",[^{]*"user"[^}]*', the_page) 402 | 403 | #Buscar videos y eliminarlos de la lista 404 | delete_list = [] 405 | if len(matchImage) > 0: 406 | for x in xrange(0, len(matchImage)): 407 | image = matchImage[x].replace('\\','') 408 | s2 = image.split('.') 409 | print s2[len(s2)-1] 410 | if(s2[len(s2)-1] == "mp4"): 411 | delete_list.append(x) 412 | removed = 0 413 | for d in delete_list: 414 | print "Removing: "+str(d-removed) 415 | del matchImage[d-removed] 416 | removed+=1 417 | #Comenzar a obtener la informacion 418 | if len(matchImage) > 0: 419 | for x in xrange(0,len(matchImage)): 420 | image = matchImage[x].replace('\\','') 421 | 422 | #Descargo la imagen 423 | s = image.split('/') 424 | image_file = s[len(s)-1] 425 | 426 | if not os.path.exists("img"): 427 | os.makedirs("img") 428 | if(not os.path.isfile("img/"+image_file)): 429 | urllib.urlretrieve(image, "img/"+image_file) 430 | 431 | 432 | self.feed['image_file'].append(image_file) 433 | caption = re.search(r'"text":"(.*?)"', matchCaption[x][1]) 434 | 435 | 436 | if matchCaption[x][0] == 'null' or caption == None: 437 | self.feed['images'].append(image) 438 | self.feed['captions'].append('') 439 | else: 440 | 441 | caption = caption.group().replace('\\','') 442 | self.feed['images'].append(image) 443 | self.feed['captions'].append(caption) 444 | 445 | #le expression: "id":(.*) 446 | matchUser = re.search(r'"user"[^}]*', matchUser1[x]) 447 | matchId = re.search(r'"id":[^},\n]*', matchUser.group(0)) 448 | matchUsername = re.search(r'"username":[^},\n]*', matchUser.group(0)) 449 | self.feed['userid'].append(matchId.group(0).split(':', 1)[1][1:-1]) 450 | self.feed['username'].append(matchUsername.group(0).split(':', 1)[1][1:-1]) 451 | 452 | comment_list = [] 453 | matchCommentText = re.findall(r'"text":"(.*?)"', matchComment[x]) 454 | matchCommentUser = re.findall(r'"username":"(.*?)"', matchComment[x]) 455 | if len(matchCommentText) > 0: 456 | for y in xrange(0, len(matchCommentText)): 457 | text = matchCommentText[y] 458 | user = matchCommentUser[y] 459 | comment_list.append( (text, user) ) 460 | self.feed['comments'].append(comment_list) 461 | 462 | """******** Funcion: Initialize ************** 463 | Descripcion: Inicializa el frame y la ventana 464 | Retorno: Sin retorno 465 | *****************************************************""" 466 | def Initialize(self): 467 | #Titulo de la ventana 468 | self.master.title("Instagram Application") 469 | 470 | #El estilo se puede cambiar despues, por ahora lo dejaremos 471 | #en gris (defecto) 472 | self.style = Style() 473 | self.style.theme_use("default") 474 | 475 | #Añadimos el canvas al frame 476 | self.canvas.pack(fill=BOTH, expand=1) 477 | 478 | #esto aun no funciona bien, la idea de esto es un scrollbar 479 | #que nos permita bajar para ver todos los comentarios. Aun no 480 | #esta listo! 481 | self.scroll = Scrollbar(self, orient=VERTICAL) 482 | self.scroll.pack(side=RIGHT, fill=Y) 483 | self.scroll.config(command=self.canvas.yview) 484 | 485 | 486 | self.GetToken() 487 | 488 | 489 | """******** Funcion: GetToken ************** 490 | Descripcion: Pide el token al usuario 491 | Retorno: Sin retorno 492 | *****************************************************""" 493 | def GetToken(self): 494 | self.token_entry = Entry(width = int(60*radio)) 495 | self.token_button = Button(text = "Ingresar", command = lambda:self.OnTokenObtained()) 496 | self.objects.append(self.canvas.create_window(int(350*radio), int(100*radio), window = self.token_entry)) 497 | self.objects.append(self.canvas.create_window(int(350*radio), int(120*radio), window = self.token_button)) 498 | self.objects.append(self.canvas.create_text(int(350*radio), int(80*radio), text = "Ingrese el token")) 499 | 500 | """******** Funcion: OnTokenObtained ************** 501 | Descripcion: Llamada una vez que se ingresa el token 502 | Retorno: Sin retorno 503 | *****************************************************""" 504 | def OnTokenObtained(self): 505 | #Sidebar + Post de prueba, aca deberiamos realizar la llamada usando el API de instagram 506 | #llenar una lista de posts y comenzar a iterar... 507 | self.token = self.token_entry.get() 508 | print "Cargando..." 509 | self.ParseFeed() 510 | self.ParseProfile() 511 | self.DrawSideBar() 512 | self.DrawPost(0) 513 | 514 | 515 | """******** Funcion: DrawFollowers ************** 516 | Descripcion: Dibuja en pantalla los seguidores y sus 517 | fotos segun la pagina 518 | Parametros: 519 | page pagina a mostrar 520 | Retorno: Sin retorno 521 | *****************************************************""" 522 | def DrawFollowers(self, page): 523 | if(page == 1): 524 | self.ParseFollowers() 525 | self.ClearContent() 526 | 527 | pages = (len(self.followers['pictures'])/12)+1 528 | if(page > pages): 529 | page = pages 530 | print pages 531 | x = 230 532 | y = 30 533 | elements_per_page = 12 534 | self.view_profile_im = [] 535 | self.view_profile_tkimg = [] 536 | #Imagen por imagen 537 | for i in range(1, elements_per_page+1): 538 | if(i+elements_per_page*(page-1) >= len(self.followers['pictures'])): 539 | break 540 | print "img/"+self.followers['pictures'][i+elements_per_page*(page-1)] 541 | self.view_profile_im.append(Image.open("img/"+self.followers['pictures'][i+elements_per_page*(page-1)])) 542 | self.view_profile_im[i-1] = self.view_profile_im[i-1].resize((int(70*radio) , int(70*radio)), Image.ANTIALIAS) 543 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[i-1])) 544 | self.objects.append(self.canvas.create_image(int(x*radio), int(y*radio), image=self.view_profile_tkimg[i-1], anchor = NW)) 545 | btn = Button(text = "Ver Perfil", command = self.DrawOtherProfile_CB(self.followers['ids'][i+elements_per_page*(page-1)], 1)) 546 | self.objects.append(self.canvas.create_window(int((x+35)*radio), int(y+80)*radio, window=btn)) 547 | x += 110 548 | if(i % 4 == 0): 549 | x = 230 550 | y += 105 551 | if(page > 1): 552 | self.back = Button(text = "Atras", command = lambda: self.DrawFollowers(page-1)) #Aca deberiamos pasar algun Id de post o lo que sea 553 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 554 | if page < pages: 555 | self.next = Button(text = "Siguiente", command = lambda: self.DrawFollowers(page+1)) 556 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 557 | 558 | 559 | """******** Funcion: DrawOtherProfile_CB ************** 560 | Descripcion: Callback para evitar problemas de scope 561 | con algunas variables al mostrar perfiles 562 | Parametros: 563 | profile perfil a buscar y parsear 564 | page pagina a mostrar 565 | Retorno: Sin retorno 566 | *****************************************************""" 567 | def DrawOtherProfile_CB(self, profile, page): 568 | return lambda:self.DrawOtherProfile(profile, page); 569 | 570 | """******** Funcion: DrawFollowing ************** 571 | Descripcion: Dibuja en pantalla a los seguidos y sus 572 | fotos segun la pagina 573 | Parametros: 574 | page pagina a mostrar 575 | Retorno: Sin retorno 576 | *****************************************************""" 577 | def DrawFollowing(self, page): 578 | if(page == 1): 579 | self.ParseFollowing() 580 | 581 | self.ClearContent() 582 | 583 | pages = (len(self.following['pictures'])/12)+1 584 | if(page > pages): 585 | page = pages 586 | print pages 587 | x = 230 588 | y = 30 589 | elements_per_page = 12 590 | self.view_profile_im = [] 591 | self.view_profile_tkimg = [] 592 | #Imagen por imagen 593 | for i in range(1, elements_per_page+1): 594 | if(i+elements_per_page*(page-1) >= len(self.following['pictures'])): 595 | break 596 | print "img/"+self.following['pictures'][i+elements_per_page*(page-1)] 597 | self.view_profile_im.append(Image.open("img/"+self.following['pictures'][i+elements_per_page*(page-1)])) 598 | self.view_profile_im[i-1] = self.view_profile_im[i-1].resize((int(70*radio) , int(70*radio)), Image.ANTIALIAS) 599 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[i-1])) 600 | self.objects.append(self.canvas.create_image(int(x*radio), int(y*radio), image=self.view_profile_tkimg[i-1], anchor = NW)) 601 | print str(i+elements_per_page*(page-1)) +"|"+ str(len(self.following['ids']))+"|"+str(len(self.following['pictures'])) 602 | btn = Button(text = "Ver Perfil", command = self.DrawOtherProfile_CB(self.following['ids'][i+elements_per_page*(page-1)], 1)) 603 | self.objects.append(self.canvas.create_window(int((x+35)*radio), int(y+80)*radio, window=btn)) 604 | x += 110 605 | if(i % 4 == 0): 606 | x = 230 607 | y += 105 608 | if(page > 1): 609 | self.back = Button(text = "Atras", command = lambda: self.DrawFollowing(page-1)) #Aca deberiamos pasar algun Id de post o lo que sea 610 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 611 | if page < pages: 612 | self.next = Button(text = "Siguiente", command = lambda: self.DrawFollowing(page+1)) 613 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 614 | 615 | """******** Funcion: DrawSearchInput ************** 616 | Descripcion: Dibuja botones y labels para buscar 617 | Retorno: Sin retorno 618 | *****************************************************""" 619 | def DrawSearchInput(self): 620 | self.ClearContent(); 621 | self.search_entry = Entry() 622 | self.objects.append(self.canvas.create_window(int(450*radio), int(40*radio), window = self.search_entry)) 623 | self.objects.append(self.canvas.create_text(int(450*radio), int(20*radio), text = "Ingrese nombre: ")) 624 | self.search_button = Button(text = "Buscar", command = lambda: self.DrawSearchReply(1, True)) 625 | self.objects.append(self.canvas.create_window(int(450*radio), int(60*radio), window = self.search_button)) 626 | 627 | 628 | """******** Funcion: DrawSearchReply ************** 629 | Descripcion: Muestra los resultados de una busqueda anterior 630 | Parametros: 631 | page pagina a mostrar 632 | parse Verdadero si se necesita volver a buscar, falso de otra manera 633 | Retorno: Sin retorno 634 | *****************************************************""" 635 | def DrawSearchReply(self, page, parse): 636 | if(parse == True): 637 | self.ParseSearch(self.search_entry.get()) 638 | self.ClearContent(); 639 | self.search_entry = Entry() 640 | self.objects.append(self.canvas.create_window(int(450*radio), int(40*radio), window = self.search_entry)) 641 | self.objects.append(self.canvas.create_text(int(450*radio), int(20*radio), text = "Ingrese nombre: ")) 642 | self.search_button = Button(text = "Buscar", command = lambda: self.DrawSearchReply(1, True)) 643 | self.objects.append(self.canvas.create_window(int(450*radio), int(60*radio), window = self.search_button)) 644 | 645 | pages = (len(self.search_reply['pictures'])/8)+1 646 | if(page > pages): 647 | page = pages 648 | print pages 649 | x = 230 650 | y = 100 651 | elements_per_page = 8 652 | self.view_profile_im = [] 653 | self.view_profile_tkimg = [] 654 | #Imagen por imagen 655 | for i in range(1, elements_per_page+1): 656 | if(i+elements_per_page*(page-1) >= len(self.search_reply['pictures'])): 657 | break 658 | print "img/"+self.search_reply['pictures'][i+elements_per_page*(page-1)] 659 | self.view_profile_im.append(Image.open("img/"+self.search_reply['pictures'][i+elements_per_page*(page-1)])) 660 | self.view_profile_im[i-1] = self.view_profile_im[i-1].resize((int(70*radio) , int(70*radio)), Image.ANTIALIAS) 661 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[i-1])) 662 | self.objects.append(self.canvas.create_image(int(x*radio), int(y*radio), image=self.view_profile_tkimg[i-1], anchor = NW)) 663 | btn = Button(text = "Ver Perfil", command = self.DrawOtherProfile_CB(self.search_reply['ids'][i+elements_per_page*(page-1)], 1)) 664 | self.objects.append(self.canvas.create_text(int((x+35)*radio), int((y+80)*radio), text = self.search_reply['names'][i+elements_per_page*(page-1)])) 665 | self.objects.append(self.canvas.create_window(int((x+35)*radio), int(y+100)*radio, window=btn)) 666 | x += 110 667 | if(i % 4 == 0): 668 | x = 230 669 | y += 120 670 | if(page > 1): 671 | self.back = Button(text = "Atras", command = lambda: self.DrawSearchReply(page-1)) #Aca deberiamos pasar algun Id de post o lo que sea 672 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 673 | if page < pages: 674 | self.next = Button(text = "Siguiente", command = lambda: self.DrawSearchReply(page+1)) 675 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 676 | 677 | 678 | 679 | """******** Funcion: DrawSideBar************** 680 | Descripcion: Dibuja el sidebar 681 | Retorno: Sin retorno 682 | *****************************************************""" 683 | #Deberia ser llamado solo una vez 684 | def DrawSideBar(self): 685 | #Linea que separa el side bar (izquierda) del contenido (derecha) 686 | self.canvas.create_line(int(200*radio), 0, int(200*radio), int(700*radio)) 687 | 688 | #Esto es solo temporal, una linea que simula en donde estara la foto de la persona 689 | print "img/"+self.profile['picture'] 690 | self.sidebar_im = Image.open("img/"+self.profile['picture']) 691 | self.sidebar_im = self.sidebar_im.resize((int(80*radio) , int(80*radio)), Image.ANTIALIAS) 692 | self.sidebar_tkimg = ImageTk.PhotoImage(self.sidebar_im) 693 | self.canvas.create_image(int(58*radio), int(40*radio), image=self.sidebar_tkimg, anchor = NW) 694 | self.sidebar_user = Label(text = self.profile['username']) 695 | self.canvas.create_window(int(100*radio), int(130*radio), window = self.sidebar_user) 696 | 697 | #Creamos los botones para cerrar el programa, aun no funciona 698 | self.exit = Button(text = "Salir", command = self.Exit) 699 | self.canvas.create_window(int(100*radio), int(375*radio), window = self.exit) 700 | self.update = Button(text = "Update", command = self.Update) 701 | self.canvas.create_window(int(100*radio), int(350*radio), window = self.update) 702 | 703 | #Creamos los botones del sidebar 704 | self.i1 = Button(text = "Inicio", width = int(23*radio), command = lambda:self.DrawPost(0)) 705 | self.i2 = Button(text = "Ver Perfil", width = int(23*radio), command = lambda:self.DrawOwnProfile(1)) 706 | self.i3 = Button(text = "Seguidores", width = int(23*radio), command = lambda:self.DrawFollowers(1)) 707 | self.i4 = Button(text = "A los que sigo", width = int(23*radio), command = lambda:self.DrawFollowing(1)) 708 | self.i5 = Button(text = "Buscar Personas", width = int(23*radio), command = lambda:self.DrawSearchInput()) 709 | self.canvas.create_window(int(100*radio), int(200*radio), window = self.i1) 710 | self.canvas.create_window(int(100*radio), int(225*radio), window = self.i2) 711 | self.canvas.create_window(int(100*radio), int(250*radio), window = self.i3) 712 | self.canvas.create_window(int(100*radio), int(275*radio), window = self.i4) 713 | self.canvas.create_window(int(100*radio), int(300*radio), window = self.i5) 714 | 715 | """******** Funcion: DrawOwnProfile ************** 716 | Descripcion: Dibuja en pantalla las fotos recientes y la 717 | informacion basica de nuestro perfil 718 | Parametros: 719 | page pagina a mostrar 720 | Retorno: Sin retorno 721 | *****************************************************""" 722 | def DrawOwnProfile(self, page): 723 | if(page == 1): 724 | self.ParseOwnRecentPhotos() 725 | self.ClearContent() 726 | 727 | #Separador horizontal 728 | self.objects.append(self.canvas.create_line(int(200*radio), int(100*radio), int(700*radio), int(100*radio))) 729 | 730 | #Foto de perfil 731 | self.view_profile_im = [] 732 | self.view_profile_tkimg = [] 733 | print "img/"+self.profile['picture'] 734 | self.view_profile_im.append(Image.open("img/"+self.profile['picture'])) 735 | self.view_profile_im[0] = self.view_profile_im[0].resize((int(80*radio) , int(80*radio)), Image.ANTIALIAS) 736 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[0])) 737 | self.objects.append(self.canvas.create_image(int(210*radio), int(10*radio), image=self.view_profile_tkimg[0], anchor = NW)) 738 | username = self.profile['username'] 739 | bio = self.profile['bio'] 740 | website = self.profile['website'] 741 | follows = self.profile['follows'] 742 | followed_by = self.profile['followed_by'] 743 | self.objects.append(self.canvas.create_text(int(450*radio), int(25*radio), text = username)) 744 | self.objects.append(self.canvas.create_text(int(450*radio), int(45*radio), text = bio, width = int(300*radio))) 745 | self.objects.append(self.canvas.create_text(int(450*radio), int(65*radio), text = website)) 746 | self.objects.append(self.canvas.create_text(int(650*radio), int(35*radio), text = "Sigues: "+follows)) 747 | self.objects.append(self.canvas.create_text(int(650*radio), int(55*radio), text = "Seguidores: "+followed_by)) 748 | 749 | 750 | 751 | pages = (len(self.view_profile['images'])/8)+1 752 | if(page > pages): 753 | page = pages 754 | print pages 755 | x = 230 756 | y = 120 757 | 758 | if(page > 1): 759 | self.back = Button(text = "Atras", command = lambda: self.DrawOwnProfile(page-1)) #Aca deberiamos pasar algun Id de post o lo que sea 760 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 761 | if page < pages: 762 | self.next = Button(text = "Siguiente", command = lambda: self.DrawOwnProfile(page+1)) 763 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 764 | 765 | #Imagen por imagen 766 | for i in range(1, 9): 767 | if(i+8*(page-1) >= len(self.view_profile['images'])): 768 | break 769 | print "img/"+self.view_profile['images'][i+8*(page-1)] 770 | self.view_profile_im.append(Image.open("img/"+self.view_profile['images'][i+8*(page-1)])) 771 | self.view_profile_im[i] = self.view_profile_im[i].resize((int(100*radio) , int(100*radio)), Image.ANTIALIAS) 772 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[i])) 773 | self.objects.append(self.canvas.create_image(int(x*radio), int(y*radio), image=self.view_profile_tkimg[i], anchor = NW)) 774 | x += 110 775 | if(i % 4 == 0): 776 | x = 230 777 | y += 110 778 | 779 | """******** Funcion: DrawOwnProfile ************** 780 | Descripcion: Dibuja en pantalla las fotos recientes y la 781 | informacion basica de cualquier otro perfil 782 | Parametros: 783 | profile perfil a buscar y parsear 784 | page pagina a mostrar 785 | Retorno: Sin retorno 786 | *****************************************************""" 787 | def DrawOtherProfile(self, profile, page): 788 | if(profile == OUR_PROFILE_ID): 789 | self.DrawOwnProfile(1) 790 | return 791 | if(page == 1): 792 | self.ParseOtherProfile(profile) 793 | self.ParseOtherRecentPhotos(profile) 794 | self.ClearContent() 795 | 796 | #Separador horizontal 797 | self.objects.append(self.canvas.create_line(int(200*radio), int(100*radio), int(700*radio), int(100*radio))) 798 | 799 | #Foto de perfil 800 | self.view_profile_im = [] 801 | self.view_profile_tkimg = [] 802 | print "img/"+self.view_profile['picture'] 803 | self.view_profile_im.append(Image.open("img/"+self.view_profile['picture'])) 804 | self.view_profile_im[0] = self.view_profile_im[0].resize((int(80*radio) , int(80*radio)), Image.ANTIALIAS) 805 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[0])) 806 | self.objects.append(self.canvas.create_image(int(210*radio), int(10*radio), image=self.view_profile_tkimg[0], anchor = NW)) 807 | username = self.view_profile['username'] 808 | bio = self.view_profile['bio'] 809 | website = self.view_profile['website'] 810 | follows = self.view_profile['follows'] 811 | followed_by = self.view_profile['followed_by'] 812 | self.objects.append(self.canvas.create_text(int(450*radio), int(25*radio), text = username)) 813 | self.objects.append(self.canvas.create_text(int(450*radio), int(45*radio), text = bio, width = int(300*radio))) 814 | self.objects.append(self.canvas.create_text(int(450*radio), int(65*radio), text = website)) 815 | self.objects.append(self.canvas.create_text(int(650*radio), int(35*radio), text = "Siguiendo: "+follows)) 816 | self.objects.append(self.canvas.create_text(int(650*radio), int(55*radio), text = "Seguidores: "+followed_by)) 817 | 818 | 819 | 820 | pages = (len(self.view_profile['images'])/8)+1 821 | if(page > pages): 822 | page = pages 823 | print pages 824 | x = 230 825 | y = 120 826 | print self.view_profile['is_followed'] == 'follows' 827 | if self.view_profile['is_followed'] == 'follows': 828 | self.follow_button = Button(text = "Unfollow", command = lambda:self.OnFollowButton(self.view_profile['profile_id'])) 829 | elif self.view_profile['is_followed'] == 'requested': 830 | self.follow_button = Button(text = "Unrequest", command = lambda: self.OnFollowButton(self.view_profile['profile_id'])) 831 | else: 832 | self.follow_button = Button(text = "Follow", command = lambda: self.OnFollowButton(self.view_profile['profile_id'])) 833 | self.objects.append(self.canvas.create_window(int(600*radio), int(80*radio), window = self.follow_button)) 834 | if(page > 1): 835 | self.back = Button(text = "Atras", command = lambda: self.DrawOtherProfile(profile, page-1)) #Aca deberiamos pasar algun Id de post o lo que sea 836 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 837 | if page < pages: 838 | self.next = Button(text = "Siguiente", command = lambda: self.DrawOtherProfile(profile, page+1)) 839 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 840 | 841 | #Imagen por imagen 842 | for i in range(1, 9): 843 | if(i+8*(page-1) >= len(self.view_profile['images'])): 844 | break 845 | print "img/"+self.view_profile['images'][i+8*(page-1)] 846 | self.view_profile_im.append(Image.open("img/"+self.view_profile['images'][i+8*(page-1)])) 847 | self.view_profile_im[i] = self.view_profile_im[i].resize((int(100*radio) , int(100*radio)), Image.ANTIALIAS) 848 | self.view_profile_tkimg.append(ImageTk.PhotoImage(self.view_profile_im[i])) 849 | self.objects.append(self.canvas.create_image(int(x*radio), int(y*radio), image=self.view_profile_tkimg[i], anchor = NW)) 850 | x += 110 851 | if(i % 4 == 0): 852 | x = 230 853 | y += 110 854 | 855 | """******** Funcion: DrawPost ************** 856 | Descripcion: Dibuja en pantalla un post especifico del FEED con 857 | su imagen, su caption, el usuario y comentarios. 858 | Parametros: 859 | post_id id relativo a la lista de posts parseados 860 | Retorno: Sin retorno 861 | *****************************************************""" 862 | def DrawPost(self, post_id): 863 | print "DRAW:"+str(post_id)+"/"+str(len(self.feed['images'])) 864 | if(post_id < 0 or post_id >= len(self.feed['images'])): 865 | return 866 | current_post = post_id 867 | self.ClearContent() 868 | 869 | #Esto ya es una publicacion!! 870 | self.objects.append(self.canvas.create_text(int(450*radio), int(15*radio), text = "Publicaciones Recientes")) 871 | print "img/"+self.feed['image_file'][post_id] 872 | self.im = Image.open("img/"+self.feed['image_file'][post_id]) 873 | self.im = self.im.resize((int(150*radio), int(150*radio)), Image.ANTIALIAS) 874 | self.tkimg = ImageTk.PhotoImage(self.im) 875 | print self.feed['userid'][post_id] + " (total"+str(len(self.feed['userid']))+")" 876 | self.imgbtn = Button(width = int(5*radio), text = "Ver perfil", command = lambda:self.DrawOtherProfile(self.feed['userid'][post_id], 1)) 877 | self.objects.append(self.canvas.create_window(int(290*radio), int(120*radio), window = self.imgbtn)) 878 | self.objects.append(self.canvas.create_text(int(450*radio), int(42*radio), text=self.feed['username'][post_id])) 879 | self.objects.append(self.canvas.create_image(int(375*radio), int(50*radio), image=self.tkimg, anchor = NW, tags = "bg_img")) 880 | #self.objects.append(self.canvas.create_text(450, 150, text = "foto persona")) 881 | #self.objects.append(self.canvas.create_line(350, 50, 550, 50)) 882 | #self.objects.append(self.canvas.create_line(350, 250, 550, 250)) 883 | #self.objects.append(self.canvas.create_line(550, 50, 550, 250)) 884 | #self.objects.append(self.canvas.create_line(350, 50, 350, 250)) 885 | comments = "" 886 | for j in xrange(0, len(self.feed['comments'][post_id])): 887 | comments += self.feed['comments'][post_id][j][1]+": "+self.feed['comments'][post_id][j][0]+"\n" 888 | 889 | self.cmt = Label(text = comments, width = int(50*radio), height = int(7*radio), bg = "white", wraplength = int(350*radio), relief = RIDGE) 890 | self.objects.append(self.canvas.create_window(int(450*radio), int(300*radio), window = self.cmt)) 891 | self.caption = Label(text = self.feed['captions'][post_id], width = int(50*radio), height = int(2*radio), wraplength = int(350*radio)) 892 | self.objects.append(self.canvas.create_window(int(450*radio), int(210*radio), window = self.caption)) 893 | #s = Scrollbar(self, orient = VERTICAL) 894 | #s.pack(side = RIGHT, fill = Y) 895 | #s.config(command=comment_canvas.yview) 896 | #comment_canvas.create_window(400, 0, window = s) 897 | #comment_canvas.create_text(0, 0, text = comments) 898 | #comment_canvas.config(yscrollcommand=s.set) 899 | #self.scrollb = Scrollbar(txt_frm, command=self.txt.yview) 900 | #self.scrollb.grid(row=0, column=1, sticky='nsew') 901 | #txt = Label 902 | #txt['yscrollcommand'] = self.scrollb.set 903 | 904 | 905 | #Estos botones van en el lugar del post 906 | 907 | if(post_id > 0): 908 | self.back = Button(text = "Atras", command = lambda: self.DrawPost(current_post-1)) #Aca deberiamos pasar algun Id de post o lo que sea 909 | self.objects.append(self.canvas.create_window(int(560*radio), int(375*radio), window = self.back)) 910 | if post_id < len(self.feed['images'])-1: 911 | self.next = Button(text = "Siguiente", command = lambda: self.DrawPost(current_post+1)) 912 | self.objects.append(self.canvas.create_window(int(650*radio), int(375*radio), window = self.next)) 913 | 914 | 915 | #Borrar los elementos del canvas para, generalmente, poner otros 916 | #No borra los del sidebar 917 | """******** Funcion: ClearContent ************** 918 | Descripcion: Borra todos los elementos de la ventana, exceptuando 919 | el sidebar 920 | Retorno: Sin retorno 921 | *****************************************************""" 922 | def ClearContent(self): 923 | for i in self.objects: 924 | self.canvas.delete(i) 925 | 926 | """******** Funcion: ClearAll ************** 927 | Descripcion: Borra todos los elementos de la ventana. 928 | Retorno: Sin retorno 929 | *****************************************************""" 930 | def ClearAll(self): 931 | self.canvas.delete('all') 932 | 933 | """******** Funcion: Update ************** 934 | Descripcion: Vuelve a parsear el contenido del feed 935 | Retorno: Sin retorno 936 | *****************************************************""" 937 | def Update(self): 938 | self.ClearAll() 939 | temp = Label(text = "Cargando...") 940 | self.objects.append(self.canvas.create_window(int(350*radio), int(200*radio), window=temp)) 941 | self.ParseProfile() 942 | self.ParseFeed() 943 | self.DrawSideBar() 944 | self.DrawPost(0) 945 | 946 | #Morir!! 947 | """******** Funcion: Exit ************** 948 | Descripcion: Termina el programa 949 | Retorno: Sin retorno 950 | *****************************************************""" 951 | def Exit(self): 952 | self.master.destroy() 953 | 954 | def main(): 955 | root = Tk() 956 | w = MainWindow(master = root) 957 | w.mainloop() 958 | 959 | if __name__ == '__main__': 960 | main() 961 | --------------------------------------------------------------------------------