diff --git a/animelist.csv.template b/animelist.csv.template new file mode 100644 index 0000000..772d8cf --- /dev/null +++ b/animelist.csv.template @@ -0,0 +1,38 @@ +url,Cartella Download,Nome,Abilitato? +https://www.animesaturn.tv/anime/Isekai-Ojisan,Isekai Ojisan,Isekai Ojisan,1 +https://www.animesaturn.tv/anime/Ajin-aaba,Ajin/Season 1,Ajin S1,1 +https://www.animesaturn.tv/anime/Dead-Mount-Death-Play,Dead Mount Death Play/Season 1,Dead Mount Death Play S1,1 +https://www.animesaturn.tv/anime/Mashle-Magic-and-Muscles,Mashle: Magic and Muscles/Season 1,Mashle: Magic And Muscles S1,1 +https://www.animesaturn.tv/anime/My-Home-Hero,My Home Hero/Season 1,My Home Hero S1,1 +https://www.animesaturn.tv/anime/Heavenly-Delusion,Heavenly Delusion/Season 1,Heavenly Delusion S1,1 +https://www.animesaturn.tv/anime/Oshi-no-Ko,Oshi no Ko/Season 1,Oshi No Ko S1,1 +https://www.animesaturn.tv/anime/Back-Street-Girls-Gokudolls-ITA-aszb,Back Street Girls: Gokudolls/Season 1,Back Street Girls: Gokudolls S1,1 +https://www.animesaturn.tv/anime/Baki-2018-ITA-aszb,Baki/Season 1,Baki S1,1 +https://www.animesaturn.tv/anime/Baki-Dai-Raitaisai-hen-ITA,Baki/Season 2, Baki S2,1 +https://www.animesaturn.tv/anime/Hanma-Baki-Son-of-Ogre-ITA,Baki/Season 3,Baki S3,1 +https://www.animesaturn.tv/anime/Beastars-ITA-aac,Beastars/Season 1,Beastars S1,1 +https://www.animesaturn.tv/anime/Beastars-2-ITA-aab,Beastars/Season 2,Beastars S2,1 +https://www.animesaturn.tv/anime/Dororo-aszbc,Dororo/Season 1,Dororo S1,1 +https://www.animesaturn.tv/anime/Gankutsuou-Il-Conte-di-Montecristo-ITA-aszb,Gankutsuou: Il Conte di Montecristo/Season 1,Gankutsuou: Il Conte di Montecristo S1,1 +https://www.animesaturn.tv/anime/Golden-Kamuy-aszb,Golden Kamuy/Season 1,Golden Kamuy S1,1 +https://www.animesaturn.tv/anime/Golden-Kamuy-2-aszb,Golden Kamuy/Season 2,Golden Kamuy S2,1 +https://www.animesaturn.tv/anime/Golden-Kamuy-3-aszb,Golden Kamuy/Season 3,Golden Kamuy S3,1 +https://www.animesaturn.tv/anime/Golden-Kamuy-4,Golden Kamuy/Season 4,Golden Kamuy S4,1 +https://www.animesaturn.tv/anime/Hinamatsuri-aszb,Hinamatsuri/Season 1,Hinamatsuri S1,1 +https://www.animesaturn.tv/anime/Inuyashiki-aszbc,Inuyashiki/Season 1,Inuyashiki S1,1 +https://www.animesaturn.tv/anime/Kiseijuu-ITA-aszb,Kiseijuu/Season 1,Kiseijuu S1,1 +https://www.animesaturn.tv/anime/Megalo-Box-aszbc,Megalo Box/Season 1,Megalo Box S1,1 +https://www.animesaturn.tv/anime/Megalo-Box-2-aszbc,Megalo Box/Season 2,Megalo Box S2,1 +https://www.animesaturn.tv/anime/NHK-ni-Youkoso-ITA-aszb,NHK/Season 1, NHK S1,1 +https://www.animesaturn.tv/anime/Odd-Taxi-aszb,Odd Taxi/Season 1,Odd Taxi S1,1 +https://www.animesaturn.tv/anime/Overlord-ITA,Overlord/Season 1,Overlord S1,1 +https://www.animesaturn.tv/anime/Overlord-2-ITA,Overlord/Season 2,Overlord S2,1 +https://www.animesaturn.tv/anime/Overlord-3-ITA,Overlord/Season 3,Overlord S3,1 +https://www.animesaturn.tv/anime/Overlord-4-ITA,Overlord/Season 4,Overlord S4,1 +https://www.animesaturn.tv/anime/Prison-School-ITA-aszb,Prison School/Season 1,Prison School S1,1 +https://www.animesaturn.tv/anime/Shimoneta-aszb,Shimoneta/Season 1,Shimoneta S1,1 +https://www.animesaturn.tv/anime/Vinland-Saga-ITA,Vinland Saga/Season 1,Vinland Saga S1,1 +https://www.animesaturn.tv/anime/Vinland-Saga-2-ITA,Vinland Saga/Season 2,Vinland Saga S2,1 +https://www.animesaturn.tv/anime/Fumetsu-no-Anata-e-aszb,Fumetsu no Anata e/Season 1,Fumetsu no Anata e S1,1 +https://www.animesaturn.tv/anime/Fumetsu-no-Anata-e-2,Fumetsu no Anata e/Season 2,Fumetsu no Anata e S2,1 +https://www.animesaturn.tv/anime/Akatsuki-no-Yona-aszb,Akatsuki no Yona/Season 1,Akatsuki No Yona S1,1 diff --git a/cfg.json.template b/cfg.json.template new file mode 100644 index 0000000..e4c22e2 --- /dev/null +++ b/cfg.json.template @@ -0,0 +1,5 @@ +{ +"DownDir":"/media/media/anime", +"DownPriority":["streamtape", "saturn", "streamhide", "legacy"], +"ServerLink":"www.animesaturn.tv" +} diff --git a/saturn-cron.sh b/saturn-cron.sh new file mode 100755 index 0000000..e6366f6 --- /dev/null +++ b/saturn-cron.sh @@ -0,0 +1,3 @@ +python3 /opt/saturn_cli/saturn_cli.py +find /mnt/storage/media/anime/ -type f -empty -delete +find /mnt/storage/media/anime/ -name *.part -delete diff --git a/saturn_cli.py b/saturn_cli.py new file mode 100644 index 0000000..1c8405c --- /dev/null +++ b/saturn_cli.py @@ -0,0 +1,182 @@ +def modulo_scarica(): + from bs4 import BeautifulSoup as bs + import csv, jsbeautifier, cloudscraper, os, re, smtplib + from email.mime.text import MIMEText + from json import loads + from datetime import datetime + #from multiprocessing.dummy import Pool as ThreadPool + from yt_dlp import YoutubeDL + + r = cloudscraper.create_scraper() + with open("animelist.csv",mode='r') as animecsv: + csvfile=csv.reader(animecsv) + file=list(csvfile) + animecsv.close() + with open("cfg.json",mode='r') as config: + configs=config.read() + configs=loads(configs) + config.close() + def get_soup(url): #dall'url outputta la soup della pagina + page=r.get(url) + data=page.text + return bs(data, features="html.parser") + def new_email(subject,body): + msg = MIMEText(body) + msg['Subject'] = subject + msg['From'] = configs['email'] + msg['To'] = configs['email'] + with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp_server: + smtp_server.login(configs['email'], configs['email_password']) + smtp_server.sendmail(configs['email'], configs['email'], msg.as_string()) + print('Email successfully sent!') + def tutti_gli_episodi(url): #trova tutti gli episodi dalla pagina descrittiva dell'anime + cosette=get_soup(url).find('div', {'class':'tab-content'}).find_all('a') + return [episodi['href'] for episodi in cosette] + def link_ep_da_url(url): #prende la pagina del "Guarda lo Streaming" e trova il link per guardarlo + #print('ledu') + cosetta=get_soup(url).find('div', {'class':"btn btn-light w-100 mt-3 mb-3"}).parent + return cosetta['href'] + def links_ep_da_scaricare(url): #prende il link output di link_ep_da_url e cerca al suo interno tutti i link di file di tutti i provider possibili ritornando un dict + #print('leds') + soup=get_soup(url) + cosetta=soup.find('div', {'class':'main-container'}).find('source') + links={} + if cosetta: + links.update({'legacy':cosetta['src']}) #legacy video format + else: + try: + links.update({'saturn':soup.findAll('script',{'type':'text/javascript'})[2].text.split('\n')[2].strip().split('"')[1]}) #new video format + except Exception as e: + pass + try: + prelink=[link['href'] for link in soup.find('div',{'class':'dropdown-menu'}).find_all('a')] + except Exception as e: + prelink=[] + for link in prelink: + try: + button=get_soup(link).find('i', {'class':'bi bi-download'}).parent + links.update({button.text.split(' ')[-1].lower():button.parent['href']}) + except Exception as e: + pass + return links + def link_down(named_urls): #prende il dict di links_ep_da_scaricare e per quanto può converte i siti in link scaricabili tramite yt-dlp + #print('link-down') + #print(named_urls) + links={} + if named_urls.get('saturn'): + links.update({'saturn':named_urls['saturn']}) + if named_urls.get('legacy'): + links.update({'legacy':named_urls['legacy']}) + if named_urls.get('streamtape'): + soup=get_soup(named_urls['streamtape']) + try: + link = soup.find_all(string=re.compile("""document.getElementById"""))[-2].split('\n')[-1].split("'") #fa magie per estrarre il link del download + links.update({'streamtape':'https:'+link[3]+link[5][3:]+'&dl=1'}) + except Exception as e: + pass + if named_urls.get('streamhide'): + soup=get_soup(named_urls['streamhide']) + try: + script=soup.find('script',attrs={"type": "text/javascript"},string=re.compile('m3u8')).text + links.update({'streamhide':[el for el in script.split('"') if 'm3u8' in el][0]}) + except Exception as e: + pass + #print(links) + return links + def scarica(lista): #la lista sarà nella forma filepath,url e prova in ordine di priorità da conf + orario=datetime.now().strftime("%d/%m/%Y %H:%M:%S") + priority=configs['DownPriority'] + urls_file=link_down(links_ep_da_scaricare(link_ep_da_url(lista[1]))) + for provider in priority: + try: + print('['+orario+']'+'Avvio download '+provider+' per '+lista[0].split('/')[-1]) + #open(lista[0], 'wb').write(r.get(urls_file['provider']).content) + with YoutubeDL({'outtmpl':{'default':lista[0]},'quiet':True,'no_warnings':True,'ignoreerrors':False,'retries':10}) as ydl: + ydl.download(urls_file[provider]) + print('['+orario+']'+'Successo per '+lista[0].split('/')[-1]) + return + except Exception as e: + print(e) + print('['+orario+']'+'Errore '+provider+' per '+lista[0].split('/')[-1]) + #lines 0 è url ep, lines 1 è cartella download, lines 2 è nome anime + lista_email=[] + for lines in file[1:]: + ora=datetime.now() + orario=ora.strftime("%d/%m/%Y %H:%M:%S") + if int(lines[3]): + try: + lista_ep=tutti_gli_episodi(lines[0]) #ho trovato la lista dei num episodi + #print(lista_ep) + if not os.path.exists(os.path.join(configs['DownDir'],lines[1])): #se la cartella down non c'è falla + os.makedirs(os.path.join(configs['DownDir'],lines[1])) + ep_gia_scar=os.listdir(os.path.join(configs['DownDir'],lines[1])) + if len(ep_gia_scar)==len(lista_ep): + print('['+orario+']'+"Nessun aggiornamento per "+lines[1]) + else: + results=[] #lista in cui ci saranno i link da scaricare + for episodi in lista_ep: + numero=episodi.split('-')[-1] #estrae il numero dell'episodio dall'url + #print(numero) + #print(lines) + if len(lines)>4 and lines[4]: #se ho la new naming convention + numerello = format(int(float(numero)),'03d') + if float(numero)%1: + virgola = '.'+format(float(numero),'.1f').split('.')[-1] + else: + virgola = '' + nome_ep=lines[2] + 'E' + numerello + virgola + '.mp4' + else: + nome_ep=lines[2]+' Ep '+ numero + '.mp4' #definisco nome dell'episodio + if nome_ep in ep_gia_scar: + print('['+orario+']'+lines[1]+'/'+nome_ep+' è già presente nella cartella') + else: #scarico l'ep mancante + filepath=os.path.join(configs['DownDir'],lines[1], nome_ep) + results.append((filepath,episodi)) + for ep in results: + scarica(ep) + lista_email.append((os.path.basename(ep[0]),0)) + ''' + print(results) + pool=ThreadPool(1) + pool.map(scarica,results) + pool.close() + pool.join() + ''' + except Exception as e: + print(e) + lista_email.append((lines[1],1)) + print('['+orario+']'+lines[1]+'/'+lines[2]+': Errore Critico ottenendo la lista episodi') + else: + print('['+orario+']'+"Skip "+lines[2]) + if configs['email']: #se nei config email è vuota non inviamo nulla + novità=[el for el in lista_email if el[1]==0] + errori=[el for el in lista_email if el[1]==1] + #so che potrei scrivere con meno controlli le righe sotto ma per facilità di lettura faccio controlli inutili + if novità and errori: + subject='Saturn_cli: Errori e Novità' + body="Yo sono usciti nuovi episodi, valli a vedere soldato ;)\n" + for el in novità: + body+=f"{ el[0] } è stato aggiunto con successo!\n" + body+="\nOhibò ci sono stati degli errori :(\n" + for el in errori: + body+=f"{ el[0] }, oof ci sono stati errori con questo anime\n" + body+="\nFine resoconto, sono sbalordito delle mie capacità o_o" + new_email(subject,body) + elif novità: + subject='Saturn_cli: Novità' + body="Yo sono usciti nuovi episodi, valli a vedere soldato ;)\n" + for el in novità: + body+=f"{ el[0] } è stato aggiunto con successo!\n" + body+="\nFine resoconto, sono sbalordito delle mie capacità o_o" + new_email(subject,body) + elif errori: + subject='Saturn_cli: Errori' + body="Ohibò ci sono stati degli errori :(\n" + for el in errori: + body+=f"{ el[0] }, oof ci sono stati errori con questo anime\n" + body+="\nFine resoconto, sono sbalordito delle mie capacità o_o" + new_email(subject,body) + +if __name__ == "__main__": + modulo_scarica() + diff --git a/serverbot.py b/serverbot.py new file mode 100644 index 0000000..4361496 --- /dev/null +++ b/serverbot.py @@ -0,0 +1,83 @@ +import requests +import telebot +from bs4 import BeautifulSoup as bs +from saturn_cli import modulo_scarica +import csv + +bot = telebot.TeleBot('5082139972:AAFIcYvf3kjLcm2msTHPODaNuXyIjPFrv9s', parse_mode=None) + +#########################func per whitelist +whitelist=["Arcnold_Wp","PlugInSheep",] +def si_puo(message): + user=message.from_user.username + if user in whitelist: + return True + else: + bot.reply_to(message, "Nice try "+str(user)) + return False +#################### +def send_welcome(message): + user=message.from_user.username + if si_puo(message): + bot.reply_to(message, get_ip()) +@bot.message_handler(commands=['scarica_animu']) +def animu(message): + user=message.from_user.username + if si_puo(message): + bot.reply_to(message, "Avvio lo scaricamento") + modulo_scarica() + bot.reply_to(message, "Ho finito di scaricare") +############blocco new anime +@bot.message_handler(commands=['new_animu']) +def new_animu(message): + user=message.from_user.username + if si_puo(message): + msg=bot.send_message(message.chat.id, """Vuoi inserire un nuovo anime? + Se si scrivi la cosa da cercare, altrimenti scrivi no""") + bot.register_next_step_handler(msg, process_scegli_anime) +def process_scegli_anime(message): + r=requests.get('https://www.animesaturn.tv/animelist?search='+message.text.strip()) + soup=bs(r.text,'html.parser') + links=soup.find_all('a',class_='badge badge-archivio badge-light') + nomi=[nome.text for nome in links] + risposta='' + for i in range(len(nomi)): + risposta=risposta+str(i)+') '+nomi[i]+'\n' + msg=bot.send_message(message.chat.id,'Quale anime inserisco (inserisci il numero oppure un "no")?\n'+risposta) + bot.register_next_step_handler(msg,process_link_step,links) +def process_link_step(message,links): + if message.text.lower()!="no": + new_entry=[] + new_entry.append(links[int(message.text)]['href']) + print(new_entry) + msg=bot.send_message(message.chat.id, """In che cartella lo salvo?""") + bot.register_next_step_handler(msg, process_folder_step, new_entry) + else: + bot.send_message(message.chat.id, """Niente allora""") +def process_folder_step(message, new_entry): + new_entry.append(message.text.strip()) + print(new_entry) + msg=bot.send_message(message.chat.id, """Qual'è la stagione di questo anime? Inserisci solo un numero per piacere""") + bot.register_next_step_handler(msg, process_nome_step, new_entry) +def process_nome_step(message, new_entry): + seas_num=format(int(message.text.strip().title()),'02d') + new_entry.append('Episode S'+seas_num) + print(new_entry) + bot.send_message(message.chat.id, str(new_entry)) + msg=bot.send_message(message.chat.id, """Così va bene?(si/NO)""") + bot.register_next_step_handler(msg, process_verifica_step, new_entry) +def process_verifica_step(message, new_entry): + if message.text.lower()=="si": + with open("animelist.csv",mode='a') as animecsv: #link,cartella,nome,1,1 + csvfile=csv.writer(animecsv) + new_entry.append("1") #scaricamento attivo + new_entry.append('1') #new naming convention + csvfile.writerow(new_entry) + bot.send_message(message.chat.id, """Anime aggiunto :)""") + else: + bot.send_message(message.chat.id, """Niente allora""") +def smartsearch_anime(ricerca): + r=requests.get('https://www.animesaturn.in/animelist?search='+ricerca) + soup=bs(r.text,'html.parser') + links=soup.find_all('a',class_='badge badge-archivio badge-light') +bot.infinity_polling(10) diff --git a/serverbot.sh b/serverbot.sh new file mode 100755 index 0000000..da56f8a --- /dev/null +++ b/serverbot.sh @@ -0,0 +1,7 @@ +if [[ -f /tmp/serverbot.running ]] ; then + exit +fi +touch /tmp/serverbot.running +cd /opt/saturn_cli +python3 serverbot.py +rm -f /tmp/serverbot.running