├── setup.py ├── LICENSE.txt ├── src └── gogoanimeapi.py └── README.md /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | 7 | setup( 8 | name="gogoanime-api", 9 | version="1.2.458", 10 | description="Unofficial API Library for Downloading Anime Dubbed and Subbed", 11 | py_modules=["gogoanimeapi"], 12 | package_dir={'': 'src'}, 13 | install_requires=["bs4", "requests", "requests_html"], 14 | extras_require={ 15 | "dev":[ 16 | "pytest", 17 | ],}, 18 | classifiers=[ 19 | "Programming Language :: Python :: 3", 20 | "Programming Language :: Python :: 3.6", 21 | "Programming Language :: Python :: 3.7", 22 | "Programming Language :: Python :: 3.8", 23 | "Programming Language :: Python :: 3.9", 24 | "Operating System :: OS Independent", 25 | ], 26 | long_description=long_description, 27 | long_description_content_type="text/markdown", 28 | url="https://github.com/BaraniARR/gogoanimeapi", 29 | author="BaraiARR", 30 | author_email="kumarbarani61@gmail.com" 31 | 32 | ) -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 BaraniARR 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. -------------------------------------------------------------------------------- /src/gogoanimeapi.py: -------------------------------------------------------------------------------- 1 | from requests_html import HTMLSession 2 | from bs4 import BeautifulSoup 3 | import requests 4 | 5 | 6 | class gogoanime(): 7 | def __init__(self, query, animeid, episode_num, genre_name, page): # Intialises the anime class 8 | self.query = query 9 | self.animeid = animeid 10 | self.episode_num = episode_num 11 | self.genre_name = genre_name 12 | self.page = page 13 | 14 | def get_search_results(query): 15 | try: 16 | url1 = f"https://gogoanime.ai//search.html?keyword={query}" 17 | session = HTMLSession() 18 | response = session.get(url1) 19 | response_html = response.text 20 | soup = BeautifulSoup(response_html, 'html.parser') 21 | animes = soup.find("ul", {"class": "items"}).find_all("li") 22 | # print(animes) 23 | res_list_search = [] 24 | for anime in animes: # For every anime found 25 | tit = anime.a["title"] 26 | urll = anime.a["href"] 27 | r = urll.split('/') 28 | res_list_search.append({"name":f"{tit}","animeid":f"{r[2]}"}) 29 | if res_list_search == []: 30 | return {"status":"204", "reason":"No search results found for the query"} 31 | else: 32 | return res_list_search 33 | except requests.exceptions.ConnectionError: 34 | return {"status":"404", "reason":"Check the host's network Connection"} 35 | 36 | def get_anime_details(animeid): 37 | try: 38 | animelink = 'https://gogoanime.ai/category/{}'.format(animeid) 39 | response = requests.get(animelink) 40 | plainText = response.text 41 | soup = BeautifulSoup(plainText, "lxml") 42 | source_url = soup.find("div", {"class": "anime_info_body_bg"}).img 43 | imgg = source_url.get('src') 44 | tit_url = soup.find("div", {"class": "anime_info_body_bg"}).h1.string 45 | lis = soup.find_all('p', {"class": "type"}) 46 | plot_sum = lis[1] 47 | pl = plot_sum.get_text().split(':') 48 | pl.remove(pl[0]) 49 | sum = "" 50 | plot_summary = sum.join(pl) 51 | type_of_show = lis[0].a['title'] 52 | ai = lis[2].find_all('a') # .find_all('title') 53 | genres = [] 54 | for link in ai: 55 | genres.append(link.get('title')) 56 | year1 = lis[3].get_text() 57 | year2 = year1.split(" ") 58 | year = year2[1] 59 | status = lis[4].a.get_text() 60 | oth_names = lis[5].get_text() 61 | lnk = soup.find(id="episode_page") 62 | ep_str = str(lnk.contents[-2]) 63 | a_tag = ep_str.split("\n")[-2] 64 | a_tag_sliced = a_tag[:-4].split(">") 65 | last_ep_range = a_tag_sliced[-1] 66 | y = last_ep_range.split("-") 67 | ep_num = y[-1] 68 | res_detail_search = {"title":f"{tit_url}", "year":f"{year}", "other_names":f"{oth_names}", "type":f"{type_of_show}", "status":f"{status}", "genre":f"{genres}", "episodes":f"{ep_num}", "image_url":f"{imgg}","plot_summary":f"{plot_summary}"} 69 | return res_detail_search 70 | except AttributeError: 71 | return {"status":"400", "reason":"Invalid animeid"} 72 | except requests.exceptions.ConnectionError: 73 | return {"status":"404", "reason":"Check the host's network Connection"} 74 | 75 | def get_episodes_link(animeid, episode_num): 76 | try: 77 | animelink = f'https://gogoanime.ai/category/{animeid}' 78 | response = requests.get(animelink) 79 | plainText = response.text 80 | soup = BeautifulSoup(plainText, "lxml") 81 | lnk = soup.find(id="episode_page") 82 | source_url = lnk.find("li").a 83 | tit_url = soup.find("div", {"class": "anime_info_body_bg"}).h1.string 84 | URL_PATTERN = 'https://gogoanime.ai/{}-episode-{}' 85 | url = URL_PATTERN.format(animeid, episode_num) 86 | srcCode = requests.get(url) 87 | plainText = srcCode.text 88 | soup = BeautifulSoup(plainText, "lxml") 89 | source_url = soup.find("li", {"class": "dowloads"}).a 90 | vidstream_link = source_url.get('href') 91 | # print(vidstream_link) 92 | URL = vidstream_link 93 | dowCode = requests.get(URL) 94 | data = dowCode.text 95 | soup = BeautifulSoup(data, "lxml") 96 | dow_url= soup.findAll('div',{'class':'dowload'}) 97 | episode_res_link = {'title':f"{tit_url}"} 98 | for i in range(len(dow_url)): 99 | Url = dow_url[i].find('a') 100 | downlink = Url.get('href') 101 | str_= Url.string 102 | str_spl = str_.split() 103 | str_spl.remove(str_spl[0]) 104 | str_original = "" 105 | quality_name = str_original.join(str_spl) 106 | episode_res_link.update({f"{quality_name}":f"{downlink}"}) 107 | return episode_res_link 108 | except AttributeError: 109 | return {"status":"400", "reason":"Invalid animeid or episode_num"} 110 | except requests.exceptions.ConnectionError: 111 | return {"status":"404", "reason":"Check the host's network Connection"} 112 | 113 | def get_by_genre(genre_name, page): 114 | try: 115 | url = f"https://gogoanime.ai/genre/{genre_name}?page={page}" 116 | response = requests.get(url) 117 | plainText = response.text 118 | soup = BeautifulSoup(plainText, "lxml") 119 | animes = soup.find("ul", {"class": "items"}).find_all("li") 120 | gen_ani_res = [{"genre":f"{genre_name}"}] 121 | gen_ani = [] 122 | for anime in animes: # For every anime found 123 | tits = anime.a["title"] 124 | urll = anime.a["href"] 125 | r = urll.split('/') 126 | gen_ani.append({"title":f"{tits}", "animeid":f"{r[2]}"}) 127 | gen_ani_res.append(gen_ani) 128 | return gen_ani_res 129 | except AttributeError or KeyError: 130 | return {"status":"400", "reason":"Invalid genre_name or page_num"} 131 | except requests.exceptions.ConnectionError: 132 | return {"status": "404", "reason": "Check the host's network Connection"} 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GogoAnimeAPI 2 | An unofficial gogoanime api Library for Python where you can get free Dubbed and Subbed Download Links of almost all Anime. 3 | The Default Dubbed anime Language is English. 4 | 5 | ## Installation 6 | ```$ pip3 install gogoanime-api``` 7 | 8 | ## Usage 9 | ### 1. Importing the Library 10 | ```from gogoanimeapi import gogoanime as anime``` 11 | ### 2. Searching Anime by Manual Input 12 | ```anime_search = anime.get_search_results(query="Tonikaku Kawaii")``` 13 | ### 14 | #### This will return a list of dictionaries containing Anime "name" and "animeid": 15 | ``` 16 | [{'name': 'Tonikaku Kawaii', 'animeid': 'tonikaku-kawaii'}, 17 | {'name': 'Tonikaku Kawaii OVA', 'animeid': 'tonikaku-kawaii-ova'}, 18 | {'name': 'Tonikaku Kawaii (Dub)', 'animeid': 'tonikaku-kawaii-dub'}] 19 | ``` 20 | ### 21 | #### Getting the name of anime search results: 22 | ``` 23 | for title in anime_search: 24 | print(title.get('name')) 25 | ``` 26 | ### 27 | #### This will print the following: 28 | ``` 29 | Tonikaku Kawaii 30 | Tonikaku Kawaii OVA 31 | Tonikaku Kawaii (Dub) 32 | ``` 33 | Likewise, You can get "animeid" by this method. 34 | ### 3. Getting Anime Details by animeid: 35 | ```anime_details = anime.get_anime_details(animeid="tonikaku-kawaii-dub")``` 36 | ### 37 | #### This will return a dictionary containing the Detials of Anime of animeid: 38 | ``` 39 | {'title': 'Tonikaku Kawaii (Dub)', 40 | 41 | 'year': '2020', 42 | 43 | 'other_names': 'Other name: TONIKAWA: Over the Moon For You, Generally Cute, Fly Me to the Moon, Generally Cute, Fly Me to the Moon', 44 | 45 | 'type': 'Fall 2020 Anime', 46 | 47 | 'status': 'Completed', 48 | 49 | 'genre': "['Comedy', 'Romance', 'Shounen']", 50 | 51 | 'episodes': '12', 52 | 53 | 'image_url': 'https://gogocdn.net/cover/tonikaku-kawaii-dub.png', 54 | 55 | 'plot_summary': " Having grown up ridiculed for his bizarre name, Nasa Yuzaki strives to be remembered for something more. Fortunately, it seems he's on the right path, ranking first in the nation's mock exams and set to enter his high school of choice.\r\n\r\nHowever, everything changes in a single night when he notices a girl across the street on his way home. Enraptured by her overwhelming cuteness, it's love at first sight for Nasa. But in his infatuated daze, he fails to notice the approaching danger speeding down the road and finds himself at death's door. Barely alive thanks to the girl's intervention, Nasa musters the courage to confess his love to her, fearing she might otherwise vanish from his life. She accepts his proposal on one condition marriage, to which Nasa gladly accepts before passing out from his injuries. Upon waking, however, the girl is nowhere to be found.\r\n\r\nAfter recovering from his injuries, Nasa tosses his previous ambitions aside and dedicates his life to finding the girl that captured his heart, yet several years pass to no avail. But one night, when an unexpected visitor comes knocking on his door, Nasa finds himself facing a woman that would forever change his world his wife." 56 | } 57 | ``` 58 | ### 59 | #### Getting a Specific detail of Anime: 60 | ``` 61 | released_year = anime_details.get('year') 62 | println(released_year) 63 | ``` 64 | #### This will return the released year of Anime: 65 | ```2020``` 66 | 67 | Likewise, You can get any details mentioned above for your app. 68 | 69 | ### 4. Getting Download Links for an Anime: 70 | ```anime_link = anime.get_episodes_link(animeid="tonikaku-kawaii-dub", episode_num=3)``` 71 | ### 72 | #### This will return a dictionary of all Available Download Links: 73 | ``` 74 | { 75 | 'title': 'Tonikaku Kawaii (Dub)', 76 | 77 | '(HDP-mp4)': 'https://storage.googleapis.com/crucial-accord-306602/CA_K18ZXRJO/23a_1616976498148615.mp4', 78 | 79 | '(360P-mp4)': 'https://cdn11.cloud9xx.com/user1342/71bf4a5b831f51fedfa37a92d297b153/EP.3.360p.mp4?token=N-YGTQyVtMUODT9DhbS_mA&expires=1617107204&id=148615', 80 | 81 | '(720P-mp4)': 'https://cdn11.cloud9xx.com/user1342/71bf4a5b831f51fedfa37a92d297b153/EP.3.720p.mp4?token=yUGXZW6qloVIekqqgaoGrw&expires=1617107204&id=148615', 82 | 83 | '(1080P-mp4)': 'https://cdn11.cloud9xx.com/user1342/71bf4a5b831f51fedfa37a92d297b153/EP.3.1080p.mp4?token=72r_zWsyDbuVeRtfkSPv4g&expires=1617107204&id=148615', 84 | 85 | 'StreamSB': 'https://streamsb.net/d/xf1j1hoaz5c2.html', 86 | 87 | 'StreamTape': 'https://streamtape.com/v/yV1vLdYe3MF18Xe/tonikaku-kawaii-dub-episode-3.mp4', 88 | 89 | 'DoodStream': 'https://dood.to/d/x8mdw63d6knl' 90 | } 91 | ``` 92 | #### 93 | You can get the links seperately by using ".get" method as above. 94 | ### 5. Browsing Anime by Genre: 95 | Availabe Genres: 96 | 97 | * action 98 | * adventure 99 | * cars 100 | * comedy 101 | * dementia 102 | * demons 103 | * drama 104 | * dub 105 | * ecchi 106 | * fantasy 107 | * game 108 | * harem 109 | * hentai - Temporarily Unavailable 110 | * historical 111 | * horror 112 | * josei 113 | * kids 114 | * magic 115 | * martial-arts 116 | * mecha 117 | * military 118 | * music 119 | * mystery 120 | * parody 121 | * police 122 | * psychological 123 | * romance 124 | * samurai 125 | * school 126 | * sci-fi 127 | * seinen 128 | * shoujo 129 | * shoujo-ai 130 | * shounen-ai 131 | * shounen 132 | * slice-of-life 133 | * space 134 | * sports 135 | * super-power 136 | * supernatural 137 | * thriller 138 | * vampire 139 | * yaoi 140 | * yuri 141 | 142 | ```browse_genre = anime.get_by_genre(genre_name="action", page=1)``` 143 | ### 144 | #### This will return a list of dictionaries containing all anime under specified Genre with page. 145 | ``` 146 | [ 147 | {'genre': 'action'}, 148 | [ 149 | {'title': 'Itai no wa Iya nano de Bougyoryoku ni Kyokufuri Shitai to Omoimasu. II', 'animeid': 'itai-no-wa-iya-nano-de-bougyoryoku-ni-kyokufuri-shitai-to-omoimasu-ii'}, 150 | {'title': 'Dungeon ni Deai wo Motomeru no wa Machigatteiru Darou ka IV', 'animeid': 'dungeon-ni-deai-wo-motomeru-no-wa-machigatteiru-darou-ka-iv'}, 151 | {'title': 'Fate/Grand Order: Shinsei Entaku Ryouiki Camelot 2 - Paladin; Agateram', 'animeid': 'fategrand-order-shinsei-entaku-ryouiki-camelot-2-paladin-agateram'}, 152 | {'title': 'Tokyo Revengers', 'animeid': 'tokyo-revengers'}, {'title': 'Edens Zero', 'animeid': 'edens-zero'}, 153 | {'title': 'Subarashiki Kono Sekai The Animation', 'animeid': 'subarashiki-kono-sekai-the-animation'}, 154 | {'title': 'Mars Red', 'animeid': 'mars-red'}, 155 | {'title': 'Boku no Hero Academia 5th Season', 'animeid': 'boku-no-hero-academia-5th-season'}, 156 | {'title': 'B: The Beginning Succession', 'animeid': 'b-the-beginning-succession'}, 157 | {'title': 'SSSS.Dynazenon', 'animeid': 'ssss-dynazenon'}, 158 | {'title': 'Hortensia Saga (TV)', 'animeid': 'hortensia-saga-tv'}, 159 | {'title': 'Kemono Jihen', 'animeid': 'kemono-jihen'}, 160 | {'title': '100-man no Inochi no Ue ni Ore wa Tatteiru 2nd Season', 'animeid': '100-man-no-inochi-no-ue-ni-ore-wa-tatteiru-2nd-season'}, 161 | {'title': 'Log Horizon: Entaku Houkai', 'animeid': 'log-horizon-entaku-houkai'}, 162 | {'title': 'Majutsushi Orphen Hagure Tabi: Kimluck-hen', 'animeid': 'majutsushi-orphen-hagure-tabi-kimluck-hen'}, 163 | {'title': 'Nanatsu no Taizai: Fundo no Shinpan', 'animeid': 'nanatsu-no-taizai-fundo-no-shinpan'}, 164 | {'title': 'Genjitsu Shugi Yuusha no Oukoku Saikenki', 'animeid': 'genjitsu-shugi-yuusha-no-oukoku-saikenki'}, 165 | {'title': 'Ore dake Haireru Kakushi Dungeon', 'animeid': 'ore-dake-haireru-kakushi-dungeon'}, 166 | {'title': 'Shuumatsu no Walküre', 'animeid': 'shuumatsu-no-walkure'}, 167 | {'title': 'Project Scard: Praeter no Kizu', 'animeid': 'project-scard-praeter-no-kizu'} 168 | ] 169 | ] 170 | ``` 171 | The last page number can't be detected because, I have no resources about that. 172 | 173 | ### 4. Error Handling 174 | #### gogoanimeapi library has some error handlers. 175 | #### 1. Error - 404 176 | If the host device does not connected to Internet, The following error will be thrown up. 177 | 178 | ```{'status': '404', 'reason': 'Check the host's network Connection'}``` 179 | #### 2. Error - 204 180 | This error occurs when no results found for a search query. 181 | 182 | ```{'status': '204', 'reason': 'No search results found for the query'}``` 183 | #### 3. Error - 400 184 | This error occurs when the user entered an incorrect data. 185 | 186 | ```{'status': '400', 'reason': 'Invalid animeid'}``` 187 | 188 | ```{'status': '400', 'reason': 'Invalid animeid or episode_num'}``` 189 | 190 | ```{'status': '400', 'reason': 'Invalid genre_name or page_num'}``` 191 | 192 | 193 | ## Copyrights © 2021 BaraniARR., 194 | 195 | ### Licensed under MIT License., 196 | --------------------------------------------------------------------------------