Skip to content

Commit 84f26bf

Browse files
authored
Merge pull request #7 from MainKronos/dev
1.5.0
2 parents 4580081 + 8c2ff74 commit 84f26bf

File tree

12 files changed

+368
-225
lines changed

12 files changed

+368
-225
lines changed

CONTRIBUTING.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Contributing
2+
3+
## Server
4+
5+
Questa sezione spiega come aggiungere alla libreia la possibilità di scaricare un episodio da un'altro server non ancora supportato.
6+
7+
|Name|Supported|
8+
|:---|:-------:|
9+
|AnimeWorld_Server|✔️|
10+
|Streamtape|✔️|
11+
|YouTube|✔️|
12+
|StreamHide||
13+
|FileMoon||
14+
|Streamtape||
15+
|Doodstream||
16+
|StreamSB||
17+
|Streamlare||
18+
19+
Per aggiungere un nuovo server basta seguire questi passi:
20+
1. Creare un file .py con il nome del server e metterlo nella cartella [servers](https://github.com/MainKronos/AnimeWorld-API/tree/master/animeworld/servers). (es `NuovoServer.py`)
21+
2. Usa questo template per la classe del nuovo server:
22+
```py
23+
from .Server import *
24+
25+
class NuovoServer(Server):
26+
def fileLink(self): # Obbligatoria
27+
"""
28+
Recupera il link diretto per il download del file dell'episodio.
29+
30+
```
31+
return str # Link del file
32+
```
33+
"""
34+
pass #TODO: da completare
35+
36+
def fileInfo(self) -> Dict[str,str]: # Opzionale
37+
"""
38+
Recupera le informazioni del file dell'episodio.
39+
40+
```
41+
return {
42+
"content_type": str, # Tipo del file, es. video/mp4
43+
"total_bytes": int, # Byte totali del file
44+
"last_modified": datetime, # Data e ora dell'ultimo aggiornamento effettuato all'episodio sul server
45+
"server_name": str, # Nome del server
46+
"server_id": int, # ID del server
47+
"url": str # url dell'episodio
48+
}
49+
```
50+
"""
51+
pass #TODO: da completare
52+
53+
def download(self, title: Optional[str]=None, folder: str='', *, hook: Callable[[Dict], None]=lambda *args:None, opt: List[str]=[]) -> Optional[str]: # Obbligatoria
54+
"""
55+
Scarica l'episodio.
56+
57+
- `title`: Nome con cui verrà nominato il file scaricato.
58+
- `folder`: Posizione in cui verrà spostato il file scaricato.
59+
- `hook`: Funzione che viene richiamata varie volte durante il download; la funzione riceve come argomento un dizionario con le seguenti chiavi:
60+
- `total_bytes`: Byte totali da scaricare.
61+
- `downloaded_bytes`: Byte attualmente scaricati.
62+
- `percentage`: Percentuale del progresso di download.
63+
- `speed`: Velocità di download (byte/s)
64+
- `elapsed`: Tempo trascorso dall'inizio del download.
65+
- `eta`: Tempo stimato rimanente per fine del download.
66+
- `status`: 'downloading' | 'finished' | 'aborted'
67+
- `filename`: Nome del file in download.
68+
- `opt`: Lista per delle opzioni aggiuntive.
69+
- `'abort'`: Ferma forzatamente il download.
70+
71+
```
72+
return str # File scaricato
73+
```
74+
"""
75+
if title is None: title = self._defTitle
76+
else: title = self._sanitize(title)
77+
78+
pass #TODO: da completare
79+
```
80+
3. Completare le varie funzioni (quelle segnate con `Opzionale` possono anche non essere completate), prendendo anche spunto dai vari server caricati nella cartella.
81+
4. Aggiungi la linea `from .NuovoServer import NuovoServer` al file [servers/__init__.py](https://github.com/MainKronos/AnimeWorld-API/tree/master/animeworld/servers/__init__.py).
82+
5. Modificare il file [episodio.py](https://github.com/MainKronos/AnimeWorld-API/tree/master/animeworld/episodio.py) aggiungendo il nome del server tra gli import ([Linea 11](https://github.com/MainKronos/AnimeWorld-API/blob/master/animeworld/episodio.py#L11)) e modificare la funzione [__setServer](https://github.com/MainKronos/AnimeWorld-API/blob/master/animeworld/episodio.py).
83+
84+
Se tutto funziona correttamente apri una richiesta di [pull](https://github.com/MainKronos/AnimeWorld-API/pulls).

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,5 @@ Per un utilizzo avanzato consultare la [documentazione](https://github.com/MainK
6161

6262
## Contributing
6363
Se volete contribuire aprendo Issue o Pull a questa libreria siete ben accetti, tutto il codice sorgente e la documentazione è reperible su [GitHub](https://github.com/MainKronos/AnimeWorld-API).
64+
65+
Se volete aggiungere un nuovo server da cui scaricare gli episodio, allora leggere la sezione [contributing](https://github.com/MainKronos/AnimeWorld-API/blob/master/CONTRIBUTING.md).

animeworld/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
from .utility import find
55
from .anime import Anime
66
from .episodio import Episodio
7-
from .server import Server
7+
from .servers import Server
88
from .exceptions import ServerNotSupported, AnimeNotAvailable, Error404, DeprecatedLibrary

animeworld/episodio.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import requests
55
from bs4 import BeautifulSoup
66
from typing import *
7+
import time
78

89
from .utility import SES
910
from .exceptions import ServerNotSupported
10-
from .server import Server, AnimeWorld_Server, YouTube, Streamtape
11-
11+
from .servers import Server, AnimeWorld_Server, YouTube, Streamtape
1212

1313
class Episodio:
1414
"""
@@ -120,17 +120,7 @@ def download(self, title: Optional[str]=None, folder: str='', *, hook: Callable[
120120
```
121121
"""
122122

123-
file = ""
124-
err = None
125-
for server in self.links:
126-
try:
127-
file = server.download(title,folder,hook=hook,opt=opt)
128-
except (ServerNotSupported, requests.exceptions.RequestException) as e:
129-
err = e
130-
else:
131-
return file
132-
133-
raise err
123+
return self.__choiceBestServer().download(title,folder,hook=hook,opt=opt)
134124

135125
# Private
136126
def __setServer(self, links: List[Dict], numero: str) -> List[Server]: # Per ogni link li posizioni nelle rispettive classi
@@ -147,7 +137,7 @@ def __setServer(self, links: List[Dict], numero: str) -> List[Server]: # Per ogn
147137
]
148138
```
149139
"""
150-
ret = [] # lista dei server
140+
ret: List[Server] = [] # lista dei server
151141
for prov in links:
152142
if prov["id"] == 4:
153143
ret.append(YouTube(prov["link"], prov["id"], prov["name"], numero))
@@ -168,4 +158,32 @@ def __sortServer(self, elem):
168158
if isinstance(elem, YouTube): return 0
169159
elif isinstance(elem, AnimeWorld_Server): return 1
170160
elif isinstance(elem, Streamtape): return 2
171-
else: return 4
161+
else: return 4
162+
163+
def __choiceBestServer(self) -> Server:
164+
"""
165+
Sceglie il server più veloce per il download dell'episodio.
166+
"""
167+
servers = self.links
168+
169+
speed_test = [{
170+
"server": x,
171+
"bytes": -1
172+
} for x in servers]
173+
174+
max_time = 0.5 # numero di secondi massimo
175+
176+
for test in speed_test:
177+
try:
178+
start = time.perf_counter()
179+
with SES.get(test["server"].fileLink(), stream = True, timeout=0.9) as r:
180+
for chunk in r.iter_content(chunk_size = 2048):
181+
if time.perf_counter() - start > max_time: break
182+
test["bytes"] += len(chunk)
183+
except (ServerNotSupported, requests.exceptions.RequestException):
184+
continue
185+
186+
speed_test = [x for x in speed_test if x["bytes"] != -1] # tolgo tutti i server che hanno generato un eccezione
187+
if len(speed_test) == 0: return servers[0] # ritorno al caso standard
188+
189+
return max(speed_test, key=lambda x: x["bytes"])["server"] # restituisco il server che ha scaricato più byte in `max_time` secondi

animeworld/exceptions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ def __init__(self, file, funName, line):
3333
super().__init__(self.message)
3434

3535
class HardStoppedDownload(Exception):
36-
"""Il file in download è stato forsatamente interrotto."""
37-
def __init__(self):
38-
self.message = "Il file in download è stato forsatamente interrotto."
36+
"""Il file in download è stato forzatamente interrotto."""
37+
def __init__(self, file:str):
38+
self.file = file
39+
self.message = f"Il file in download ({file}) è stato forzatamente interrotto."
3940
super().__init__(self.message)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from bs4 import BeautifulSoup
2+
import re
3+
4+
from .Server import *
5+
from ..utility import HealthCheck
6+
7+
class AnimeWorld_Server(Server):
8+
@HealthCheck
9+
def fileLink(self) -> str:
10+
"""
11+
Recupera il link diretto per il download del file dell'episodio.
12+
13+
```
14+
return str # Link del file
15+
```
16+
"""
17+
18+
return self.link.replace('download-file.php?id=', '')
19+
20+
def fileInfo(self) -> Dict[str,str]:
21+
"""
22+
Recupera le informazioni del file dell'episodio.
23+
24+
```
25+
return {
26+
"content_type": str, # Tipo del file, es. video/mp4
27+
"total_bytes": int, # Byte totali del file
28+
"last_modified": datetime, # Data e ora dell'ultimo aggiornamento effettuato all'episodio sul server
29+
"server_name": str, # Nome del server
30+
"server_id": int, # ID del server
31+
"url": str # url dell'episodio
32+
}
33+
```
34+
"""
35+
36+
return self._fileInfoIn()
37+
38+
def download(self, title: Optional[str]=None, folder: str='', *, hook: Callable[[Dict], None]=lambda *args:None, opt: List[str]=[]) -> Optional[str]:
39+
"""
40+
Scarica l'episodio.
41+
42+
- `title`: Nome con cui verrà nominato il file scaricato.
43+
- `folder`: Posizione in cui verrà spostato il file scaricato.
44+
- `hook`: Funzione che viene richiamata varie volte durante il download; la funzione riceve come argomento un dizionario con le seguenti chiavi:
45+
- `total_bytes`: Byte totali da scaricare.
46+
- `downloaded_bytes`: Byte attualmente scaricati.
47+
- `percentage`: Percentuale del progresso di download.
48+
- `speed`: Velocità di download (byte/s)
49+
- `elapsed`: Tempo trascorso dall'inizio del download.
50+
- `eta`: Tempo stimato rimanente per fine del download.
51+
- `status`: 'downloading' | 'finished' | 'aborted'
52+
- `filename`: Nome del file in download.
53+
- `opt`: Lista per delle opzioni aggiuntive.
54+
- `'abort'`: Ferma forzatamente il download.
55+
56+
```
57+
return str # File scaricato
58+
```
59+
"""
60+
if title is None: title = self._defTitle
61+
else: title = self._sanitize(title)
62+
return self._downloadIn(title,folder,hook=hook,opt=opt)

0 commit comments

Comments
 (0)