├── LICENSE ├── README.md ├── posterpy.py └── requirements.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sameera Madushan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PosterPy 2 | 3 | This is a python script that helps you to search, download movie posters and set them as folder icons. PosterPy uses the popular [IMDbPY](https://imdbpy.github.io/) package to search movies and [TMDb a.k.a The Movie Data Base](https://www.themoviedb.org/) API to download movie posters. 4 | 5 | ![iaa1](https://user-images.githubusercontent.com/55880211/80022395-a2b95700-84f9-11ea-8dca-d0f0eff217bd.gif) 6 | 7 | ## For Your Attention 8 | 9 | - Your PC may take some time to index the newly added icons. If the icons doesn't appear after 3 - 5 minutes try clearing and resetting thumbnail cache of our PC. [Here](https://www.sevenforums.com/tutorials/10797-thumbnail-cache-clear-reset.html) is a article on how to clear and reset thumbnail cache in Windows. 10 | 11 | - Since PosterPy is using the TMDb API to download movie posters you need to have a TMDb API key in order to use this script. To register for an API key click [here](https://www.themoviedb.org/account/signup). Once you register an account [this](https://developers.themoviedb.org/3/getting-started/introduction) will help you to request and find your API key. (This is an one time process. Once you obatin your API key you need to enter it to the script when it ask for the key and that's it.) 12 | 13 | ## I don't like these icons. How do i remove them? 14 | 15 | To remove the poster icon from a folder, just delete the .ico and desktop.ini file from the folder. desktop.ini file is hidden by default. Therefore make sure you have __Show Hidden Items__ option ticked. 16 | 17 | ## Screenshot 18 | 19 | ![Untitled collage](https://user-images.githubusercontent.com/55880211/80029365-4f98d180-8504-11ea-84e3-f94a1fe64e09.png) 20 | 21 | ## Git Installation 22 | ``` 23 | # clone the repo 24 | $ git clone https://github.com/sameera-madushan/PosterPy.git 25 | 26 | # change the working directory to PosterPy 27 | $ cd PosterPy 28 | 29 | # install the requirements 30 | $ pip3 install -r requirements.txt 31 | ``` 32 | 33 | ## Usage 34 | 35 | ``` 36 | python posterpy.py 37 | ``` 38 | 39 | ## Support & Contributions 40 | - Please ⭐️ this repository if this project helped you! 41 | - Contributions of any kind welcome! 42 | 43 | Buy Me A Coffee 44 | 45 | ## License 46 | PosterPy is made with ♥ by [@_\_sa_miya__](https://twitter.com/__sa_miya__) and it is released under the MIT license. 47 | 48 | ## Contributors 49 | 50 | Thanks goes to this wonderful person. :heart: 51 | 52 | 53 | 54 | 55 | 56 |

Siddharth Dushantha
57 | 58 | ## Attribution 59 | 60 |

61 | 62 | Movie posters are powered by themoviedb.org 63 |

64 | -------------------------------------------------------------------------------- /posterpy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coded by sameera madushan 3 | 4 | import os 5 | import shutil 6 | from tkinter import Tk, filedialog 7 | import requests 8 | from PIL import Image, ImageOps 9 | from tqdm import tqdm 10 | import imdb 11 | import questionary 12 | 13 | banner = (r''' 14 | 15 | 16 | ooooooooo. . ooooooooo. 17 | `888 `Y88. .o8 `888 `Y88. 18 | 888 .d88' .ooooo. .oooo.o .o888oo .ooooo. oooo d8b 888 .d88' oooo ooo 19 | 888ooo88P' d88' `88b d88( "8 888 d88' `88b `888""8P 888ooo88P' `88. .8' 20 | 888 888 888 `"Y88b. 888 888ooo888 888 888 `88..8' 21 | 888 888 888 o. )88b 888 . 888 .o 888 888 `888' 22 | o888o `Y8bod8P' 8""888P' "888" `Y8bod8P' d888b o888o .8' 23 | .o..P' 24 | `Y8P' 25 | 26 |                               27 | ''') 28 | 29 | print(banner) 30 | 31 | def api_key(): 32 | 33 | SAMPLE_URL = 'https://api.themoviedb.org/3/movie/76341?api_key={0}' 34 | try: 35 | while True: 36 | if os.path.exists("api.txt") and os.path.getsize("api.txt") > 0: 37 | f = open("api.txt", "r") 38 | key = f.read() 39 | req = requests.get(SAMPLE_URL.format(key)) 40 | if req.status_code == 200: 41 | print("\nAPI Key authentication successful.\n") 42 | return key 43 | else: 44 | pass 45 | 46 | print("\nTo register for an API key, Visit: https://www.themoviedb.org/account/signup") 47 | get_key = input("API key required. Please enter the API key: ") 48 | req = requests.get(SAMPLE_URL.format(get_key)) 49 | if req.status_code == 200: 50 | f = open("api.txt", "w") 51 | f.write(get_key) 52 | f.close() 53 | else: 54 | print("\nInvalid API key: You must be granted a valid key.") 55 | except OSError: 56 | print("\nUnknown Error") 57 | 58 | def search_movie(): 59 | 60 | try: 61 | ia = imdb.IMDb() 62 | user_input = input("Search for a movie: ") 63 | print("\n", end="") 64 | movies = ia.search_movie(user_input) 65 | 66 | choices_list = [] 67 | 68 | for i in movies: 69 | get_title = i['title'] 70 | get_id = i.movieID 71 | try: 72 | get_year = i['year'] 73 | except KeyError: 74 | pass 75 | p = ("{: <10}".format(str(get_id))+ get_title + " " + "(" + str(get_year) + ")") 76 | choices_list.append(p) 77 | 78 | movie_list = questionary.select("Oh! there's alot. What did you mean? ", choices=choices_list).ask() 79 | get_id = movie_list.split() 80 | IMDB_ID = get_id[0] 81 | 82 | return IMDB_ID 83 | 84 | except KeyboardInterrupt: 85 | print("\nKeyboard Interrupted") 86 | quit() 87 | except AttributeError: 88 | quit() 89 | except ValueError: 90 | print("\nUnknown movie name.") 91 | quit() 92 | 93 | def get_image_url(): 94 | 95 | for k, v in req.items(): 96 | for i in v: 97 | for k, v in i.items(): 98 | if k == 'poster_path': 99 | image_url = 'http://image.tmdb.org/t/p/w500/' + v 100 | return [image_url, v] 101 | # if i['poster_path'] is None: 102 | # print("No Poster Found") 103 | # quit() 104 | 105 | URL = 'https://api.themoviedb.org/3/find/tt{0}?api_key={1}&language=en-US&external_source=imdb_id'.format(search_movie(), api_key()) 106 | 107 | req = requests.get(URL).json() 108 | 109 | def download_poster(): 110 | 111 | if get_image_url() is None: 112 | print("\nNo poster found") 113 | quit() 114 | else: 115 | returning_list = get_image_url() 116 | url = returning_list[0] 117 | filename = returning_list[1] 118 | _response = requests.get(url).content 119 | file_size_request = requests.get(url, stream=True) 120 | file_size = int(file_size_request.headers['Content-Length']) 121 | block_size = 1024 122 | t = tqdm(total=file_size, unit='B', unit_scale=True, desc="Downloading", ascii=True) 123 | with open(filename[1:], 'wb') as f: 124 | for data in file_size_request.iter_content(block_size): 125 | t.update(len(data)) 126 | f.write(data) 127 | t.close() 128 | print("\nPoster downloaded successfully\n") 129 | return os.getcwd() + filename 130 | 131 | def convert(): 132 | 133 | # this discussion helped me a lot: https://stackoverflow.com/questions/765736/using-pil-to-make-all-white-pixels-transparent 134 | 135 | icon = os.getcwd() + "\\poster.ico" 136 | img = Image.open(download_poster()) 137 | img = ImageOps.expand(img, (69, 0, 69, 0), fill=0) 138 | img = ImageOps.fit(img, (300, 300)).convert("RGBA") 139 | 140 | datas = img.getdata() 141 | newData = [] 142 | for item in datas: 143 | if item[0] == 0 and item[1] == 0 and item[2] == 0: 144 | newData.append((0, 0, 0, 0)) 145 | else: 146 | newData.append(item) 147 | 148 | img.putdata(newData) 149 | img.save(icon) 150 | img.close() 151 | print("Poster icon created successfully.") 152 | return icon 153 | 154 | 155 | def tk_get_file_path(): 156 | 157 | try: 158 | root = Tk() 159 | root.withdraw() 160 | file_path = filedialog.askdirectory(parent=root, title='Select folder') 161 | if file_path: 162 | return file_path 163 | else: 164 | print("\nCancelled") 165 | quit() 166 | except IOError: 167 | print("\nError Occurred.") 168 | quit() 169 | 170 | 171 | def change_folder_icon(): 172 | 173 | get_folder = tk_get_file_path() 174 | get_poster_icon = convert() 175 | 176 | if os.path.isfile(get_folder + "\\poster.ico"): 177 | print('\nAn icon is already present. Delete the older icon before applying a new icon.') 178 | quit() 179 | else: 180 | icon_to_folder = shutil.move(get_poster_icon, get_folder) 181 | 182 | if os.path.isfile(get_folder + "\\desktop.ini"): 183 | print('\nA desktop.ini file is already present. Delete the older one before applying a new one.') 184 | else: 185 | with open(get_folder + "\\desktop.ini", "w+") as f: 186 | f.write("[.ShellClassInfo]\n") 187 | f.write("IconResource=poster.ico,0") 188 | 189 | os.system('attrib +r \"{}\"'.format(get_folder)) 190 | os.system('attrib +h \"{}\\desktop.ini\"'.format(get_folder)) 191 | 192 | print("Folder icon changed successfully.") 193 | 194 | 195 | change_folder_icon() 196 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | IMDbPY==6.8 2 | Pillow==9.0.0 3 | questionary==1.5.2 4 | tqdm==4.43.0 5 | requests==2.23.0 6 | --------------------------------------------------------------------------------