├── .gitignore ├── LICENSE ├── README.md ├── Spacefile ├── main.py ├── requirements.txt └── templates ├── base.html ├── browse.html ├── cards.html ├── play.html ├── search.html ├── trending.html └── video.html /.gitignore: -------------------------------------------------------------------------------- 1 | .space -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 hanimebeast 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 | 2 | 3 | 4 | # HanimeAPI 5 | [![Donate](https://img.shields.io/badge/Donate-Buy%20Me%20a%20Coffee-orange.svg)](https://www.buymeacoffee.com/immodded) 6 | 7 | [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/hanimebeast/hanimeapi/blob/main/LICENSE) 8 | [![Telegram](https://img.shields.io/badge/Contact-%40immodded-blue.svg)](https://t.me/immodded) 9 | ![Stars](https://img.shields.io/github/stars/hanimebeast/hanimeapi?style=social) 10 | ![Forks](https://img.shields.io/github/forks/hanimebeast/hanimeapi?style=social) 11 | 12 | 13 | ## support this project 14 | https://www.buymeacoffee.com/immodded 15 | 16 | ## License 17 | 18 | HanimeAPI is licensed under the [MIT License](LICENSE). 19 | 20 | ## Contact 21 | 22 | If you have any questions, suggestions, or just want to say hi, feel free to reach out on Telegram: 23 | 24 | [![Telegram](https://img.shields.io/badge/Contact-%40immodded-blue.svg)](https://t.me/immodded) 25 | 26 | We appreciate your interest in this project! 27 | -------------------------------------------------------------------------------- /Spacefile: -------------------------------------------------------------------------------- 1 | # Spacefile Docs: https://go.deta.dev/docs/spacefile/v0 2 | v: 0 3 | micros: 4 | - name: hanimeapi 5 | src: ./ 6 | engine: python3.9 7 | public: true 8 | run: gunicorn main:app 9 | commands: 10 | - pip install -r requirements.txt 11 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, Response, jsonify, render_template, request, redirect, url_for 2 | import requests 3 | import secrets 4 | import json 5 | import os 6 | 7 | 8 | api_base = "https://modd-hanime-api.onrender.com" 9 | 10 | 11 | def get_data(api_url): 12 | api_key = os.environ.get('API_KEY') 13 | if not api_key: 14 | print("API key not found in environment variables.") 15 | return None 16 | headers = {'X-API-Key': api_key} 17 | try: 18 | response = requests.get(api_url, headers=headers) 19 | 20 | if response.status_code == 200: 21 | return response.json() 22 | else: 23 | print(f"Error: {response.status_code}") 24 | return None 25 | 26 | except Exception as e: 27 | print(f"An error occurred: {e}") 28 | return None 29 | 30 | 31 | def gettrending(time,page): 32 | jsondata = [] 33 | page = page 34 | trending_url = f"{api_base}/trending?time={time}&page={page}" 35 | url = trending_url 36 | urldata = get_data(url) 37 | for x in urldata["hentai_videos"]: 38 | json_data = {'id': x['id'] , 'name' : x['name'],'slug' : x['slug'],'url': "/video/"+x['slug'] , 'cover_url': x['cover_url'], 'views' : x['views'], 'link': f"/api/video/{x['slug']}"} 39 | jsondata.append(json_data) 40 | return jsondata 41 | 42 | def getvideo(slug): 43 | jsondata = [] 44 | video_api_url = f"{api_base}/video?slug=" 45 | video_data_url = video_api_url + slug 46 | video_data = get_data(video_data_url) 47 | tags = [] 48 | for t in video_data['hentai_tags']: 49 | tag_data = {'name' : t['text'], 'link' : f"/browse/hentai-tags/{t['text']}/0"} 50 | tags.append(tag_data) 51 | streams = [] 52 | for s in video_data['videos_manifest']['servers'][0]['streams']: 53 | stream_data = {'width' : s['width'],'height' : s['height'],'size_mbs' : s['filesize_mbs'],'url' : s['url'],'link': s['url']} 54 | streams.append(stream_data) 55 | episodes = [] 56 | for e in video_data['hentai_franchise_hentai_videos']: 57 | episodes_data = {'id': e['id'] , 'name' : e['name'],'slug' : e['slug'], 'cover_url': e['cover_url'], 'views' : e['views'], 'link': f"/api/video/{e['slug']}"} 58 | episodes.append(episodes_data) 59 | json_data = {'id': video_data["hentai_video"]['id'] , 'name' : video_data["hentai_video"]['name'],'description': video_data["hentai_video"]['description'], 'poster_url': video_data["hentai_video"]['poster_url'],'cover_url': video_data["hentai_video"]['cover_url'], 'views' : video_data["hentai_video"]['views'], 'streams': streams, 'tags': tags , 'episodes' : episodes} 60 | jsondata.append(json_data) 61 | return jsondata 62 | 63 | def getbrowse(): 64 | browse_url = f"{api_base}/browse" 65 | data = get_data(browse_url) 66 | return data 67 | 68 | def getbrowsevideos(type,category,page): 69 | browse_url = f"{api_base}/getbrowsevideos?page={page}&type={type}&category={category}" 70 | browsedata = get_data(browse_url) 71 | jsondata = [] 72 | for x in browsedata["hentai_videos"]: 73 | json_data = {'id': x['id'] , 'name' : x['name'],'slug' : x['slug'], 'cover_url': x['cover_url'], 'views' : x['views'], 'link': f"/api/video/{x['slug']}"} 74 | jsondata.append(json_data) 75 | return jsondata 76 | 77 | def getsearch(query, page): 78 | search_url = f"{api_base}/search?query={query}&page={page}" 79 | data = get_data(search_url) 80 | videos = json.loads(data['hits']) 81 | total_pages = data['nbPages'] 82 | data = {'total_pages':total_pages,'videos':videos} 83 | jsondata = [] 84 | for x in data["videos"]: 85 | json_data = {'id': x['id'] , 'name' : x['name'],'slug' : x['slug'],'url': "/video/"+x['slug'], 'cover_url': x['cover_url'], 'views' : x['views'], 'link': f"/api/video/{x['slug']}"} 86 | jsondata.append(json_data) 87 | return jsondata 88 | 89 | app = Flask(__name__) 90 | @app.route('/') 91 | def index(): 92 | return redirect("/trending/month/0") 93 | 94 | @app.route('/search', methods=['GET', 'POST']) 95 | def search(): 96 | if request.method == 'POST': 97 | search_query = request.form['search_query'] 98 | redirect_url = url_for('search', query=search_query, page=0) 99 | return redirect(redirect_url) 100 | query = request.args.get('query') 101 | page = request.args.get('page', default=0, type=int) 102 | videos = getsearch(query,page) 103 | next_page = f'/search?query={query}&page={int(page)+1}' 104 | return render_template('search.html',videos=videos, next_page = next_page, query = query) 105 | 106 | @app.route('/trending/