refactor(allanime provider):clean up and move allanime api to allanime folder
|
Before Width: | Height: | Size: 971 KiB After Width: | Height: | Size: 971 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 690 KiB After Width: | Height: | Size: 690 KiB |
|
Before Width: | Height: | Size: 718 KiB After Width: | Height: | Size: 718 KiB |
|
Before Width: | Height: | Size: 813 KiB After Width: | Height: | Size: 813 KiB |
|
Before Width: | Height: | Size: 763 KiB After Width: | Height: | Size: 763 KiB |
|
Before Width: | Height: | Size: 518 KiB After Width: | Height: | Size: 518 KiB |
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 578 KiB |
|
Before Width: | Height: | Size: 644 KiB After Width: | Height: | Size: 644 KiB |
|
Before Width: | Height: | Size: 566 KiB After Width: | Height: | Size: 566 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
@@ -1,116 +1,22 @@
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
|
||||
import requests
|
||||
|
||||
# TODO: move constants to own file
|
||||
ALLANIME_BASE = "allanime.day"
|
||||
ALLANIME_REFERER = "https://allanime.to/"
|
||||
ALLANIME_API_ENDPOINT = "https://api.{}/api/".format(ALLANIME_BASE)
|
||||
from .gql_queries import ALLANIME_SHOW_GQL, ALLANIME_SEARCH_GQL, ALLANIME_EPISODES_GQL
|
||||
from .constants import (
|
||||
ALLANIME_BASE,
|
||||
ALLANIME_REFERER,
|
||||
ALLANIME_API_ENDPOINT,
|
||||
USER_AGENT,
|
||||
)
|
||||
from .utils import decode_hex_string
|
||||
from .data_types import (
|
||||
AllAnimeEpisode,
|
||||
AllAnimeSearchResults,
|
||||
)
|
||||
|
||||
|
||||
# TODO: move th gql queries to own files
|
||||
ALLANIME_SEARCH_GQL = """
|
||||
query(
|
||||
$search: SearchInput
|
||||
$limit: Int
|
||||
$page: Int
|
||||
$translationType: VaildTranslationTypeEnumType
|
||||
$countryOrigin: VaildCountryOriginEnumType
|
||||
) {
|
||||
shows(
|
||||
search: $search
|
||||
limit: $limit
|
||||
page: $page
|
||||
translationType: $translationType
|
||||
countryOrigin: $countryOrigin
|
||||
) {
|
||||
pageInfo {
|
||||
total
|
||||
}
|
||||
edges {
|
||||
_id
|
||||
name
|
||||
availableEpisodes
|
||||
__typename
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
ALLANIME_EPISODES_GQL = """\
|
||||
query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) {
|
||||
episode(
|
||||
showId: $showId
|
||||
translationType: $translationType
|
||||
episodeString: $episodeString
|
||||
) {
|
||||
|
||||
episodeString
|
||||
sourceUrls
|
||||
notes
|
||||
}
|
||||
}"""
|
||||
|
||||
ALLANIME_SHOW_GQL = """
|
||||
query ($showId: String!) {
|
||||
show(
|
||||
_id: $showId
|
||||
) {
|
||||
|
||||
_id
|
||||
name
|
||||
availableEpisodesDetail
|
||||
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# TODO: creat a utility module for this
|
||||
# Dictionary to map hex values to characters
|
||||
hex_to_char = {
|
||||
"01": "9",
|
||||
"08": "0",
|
||||
"05": "=",
|
||||
"0a": "2",
|
||||
"0b": "3",
|
||||
"0c": "4",
|
||||
"07": "?",
|
||||
"00": "8",
|
||||
"5c": "d",
|
||||
"0f": "7",
|
||||
"5e": "f",
|
||||
"17": "/",
|
||||
"54": "l",
|
||||
"09": "1",
|
||||
"48": "p",
|
||||
"4f": "w",
|
||||
"0e": "6",
|
||||
"5b": "c",
|
||||
"5d": "e",
|
||||
"0d": "5",
|
||||
"53": "k",
|
||||
"1e": "&",
|
||||
"5a": "b",
|
||||
"59": "a",
|
||||
"4a": "r",
|
||||
"4c": "t",
|
||||
"4e": "v",
|
||||
"57": "o",
|
||||
"51": "i",
|
||||
}
|
||||
|
||||
|
||||
def decode_hex_string(hex_string):
|
||||
# Split the hex string into pairs of characters
|
||||
hex_pairs = re.findall("..", hex_string)
|
||||
|
||||
# Decode each hex pair
|
||||
decoded_chars = [hex_to_char.get(pair.lower(), pair) for pair in hex_pairs]
|
||||
|
||||
return "".join(decoded_chars)
|
||||
Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: create tests for the api
|
||||
@@ -122,24 +28,22 @@ class AllAnimeAPI:
|
||||
|
||||
api_endpoint = ALLANIME_API_ENDPOINT
|
||||
|
||||
def _fetch_gql(self, query: str, variables: dict):
|
||||
def _fetch_gql(self, query: str, variables: dict) -> dict:
|
||||
response = requests.get(
|
||||
self.api_endpoint,
|
||||
params={
|
||||
"variables": json.dumps(variables),
|
||||
"query": query,
|
||||
},
|
||||
headers={
|
||||
"Referer": ALLANIME_REFERER,
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
|
||||
},
|
||||
headers={"Referer": ALLANIME_REFERER, "User-Agent": USER_AGENT},
|
||||
)
|
||||
if response.status_code != 200:
|
||||
print(response.content)
|
||||
return {}
|
||||
return response.json().get("data", {})
|
||||
|
||||
def search_for_anime(self, user_query: str, translation_type: str = "sub"):
|
||||
def search_for_anime(
|
||||
self, user_query: str, translation_type: str = "sub"
|
||||
) -> AllAnimeSearchResults | dict:
|
||||
search = {"allowAdult": False, "allowUnknown": False, "query": user_query}
|
||||
limit = 40
|
||||
translationtype = translation_type
|
||||
@@ -160,7 +64,7 @@ class AllAnimeAPI:
|
||||
|
||||
def get_anime_episode(
|
||||
self, allanime_show_id: str, episode_string: str, translation_type: str = "sub"
|
||||
):
|
||||
) -> AllAnimeEpisode | dict:
|
||||
variables = {
|
||||
"showId": allanime_show_id,
|
||||
"translationType": translation_type,
|
||||
@@ -190,23 +94,27 @@ class AllAnimeAPI:
|
||||
embed_url,
|
||||
headers={
|
||||
"Referer": ALLANIME_REFERER,
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
|
||||
"User-Agent": USER_AGENT,
|
||||
},
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
match embed["sourceName"]:
|
||||
case "Luf-mp4":
|
||||
Logger.debug("allanime:Found streams from gogoanime")
|
||||
yield "gogoanime", resp.json()
|
||||
case "Kir":
|
||||
Logger.debug("allanime:Found streams from wetransfer")
|
||||
yield "wetransfer", resp.json()
|
||||
case "S-mp4":
|
||||
Logger.debug("allanime:Found streams from sharepoint")
|
||||
yield "sharepoint", resp.json()
|
||||
case "Sak":
|
||||
Logger.debug("allanime:Found streams from dropbox")
|
||||
yield "dropbox", resp.json()
|
||||
case _:
|
||||
yield "Unknown", resp.json()
|
||||
else:
|
||||
return None
|
||||
return {}
|
||||
|
||||
|
||||
anime_provider = AllAnimeAPI()
|
||||
@@ -216,30 +124,7 @@ if __name__ == "__main__":
|
||||
# lets see if it works :)
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run_fzf(options):
|
||||
"""
|
||||
Run fzf with a list of options and return the selected option.
|
||||
"""
|
||||
# Join the list of options into a single string with newlines
|
||||
options_str = "\n".join(options)
|
||||
|
||||
# Run fzf as a subprocess
|
||||
result = subprocess.run(
|
||||
["fzf"],
|
||||
input=options_str,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
|
||||
# Check if fzf was successful
|
||||
if result.returncode == 0:
|
||||
# Return the selected option
|
||||
return result.stdout.strip()
|
||||
else:
|
||||
# Handle the case where fzf fails or is canceled
|
||||
print("fzf was canceled or failed")
|
||||
return None
|
||||
from .utils import run_fzf
|
||||
|
||||
anime = input("Enter the anime name: ")
|
||||
translation = input("Enter the translation type: ")
|
||||
@@ -247,7 +132,7 @@ if __name__ == "__main__":
|
||||
search_results = anime_provider.search_for_anime(
|
||||
anime, translation_type=translation.strip()
|
||||
)
|
||||
print(search_results)
|
||||
|
||||
if not search_results:
|
||||
raise Exception("No results found")
|
||||
|
||||
@@ -260,7 +145,6 @@ if __name__ == "__main__":
|
||||
|
||||
anime_result = list(filter(lambda x: x["name"] == anime, search_results))[0]
|
||||
anime_data = anime_provider.get_anime(anime_result["_id"])
|
||||
print(anime_data)
|
||||
if anime_data is None:
|
||||
raise Exception("Anime not found")
|
||||
availableEpisodesDetail = anime_data["show"]["availableEpisodesDetail"]
|
||||
@@ -284,11 +168,14 @@ if __name__ == "__main__":
|
||||
if not episode_streams:
|
||||
raise Exception("No streams found")
|
||||
episode_streams = list(episode_streams)
|
||||
print(episode_streams)
|
||||
stream_links = []
|
||||
for server in episode_streams:
|
||||
stream_links = [
|
||||
*stream_links,
|
||||
*[stream["link"] for stream in server[1]["links"]],
|
||||
]
|
||||
stream_links = stream_link = run_fzf([*stream_links, "quit"])
|
||||
|
||||
stream_links = [stream["link"] for stream in episode_streams[2][1]["links"]]
|
||||
stream_link = run_fzf([*stream_links, "quit"])
|
||||
print(stream_link)
|
||||
if stream_link == "quit":
|
||||
print("Have a nice day")
|
||||
sys.exit()
|
||||
4
fastanime/libs/anime_provider/allanime/constants.py
Normal file
@@ -0,0 +1,4 @@
|
||||
ALLANIME_BASE = "allanime.day"
|
||||
ALLANIME_REFERER = "https://allanime.to/"
|
||||
ALLANIME_API_ENDPOINT = "https://api.{}/api/".format(ALLANIME_BASE)
|
||||
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
|
||||
49
fastanime/libs/anime_provider/allanime/data_types.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class AllAnimeEpisodesInfo(TypedDict):
|
||||
dub: int
|
||||
sub: int
|
||||
raw: int
|
||||
|
||||
|
||||
class AllAnimePageInfo(TypedDict):
|
||||
total: int
|
||||
|
||||
|
||||
class AllAnimeShow(TypedDict):
|
||||
_id: str
|
||||
name: str
|
||||
availableEpisodes: AllAnimeEpisodesInfo
|
||||
__typename: str
|
||||
|
||||
|
||||
class AllAnimeShows(TypedDict):
|
||||
pageInfo: AllAnimePageInfo
|
||||
edges: list[AllAnimeShow]
|
||||
|
||||
|
||||
class AllAnimeSearchResults(TypedDict):
|
||||
shows: AllAnimeShows
|
||||
|
||||
|
||||
class AllAnimeSourcesDownloads(TypedDict):
|
||||
sourceName: str
|
||||
dowloadUrl: str
|
||||
|
||||
|
||||
class AllAnimeSources(TypedDict):
|
||||
sourceUrl: str
|
||||
priority: float
|
||||
sandbox: str
|
||||
sourceName: str
|
||||
type: str
|
||||
className: str
|
||||
streamerId: str
|
||||
downloads: AllAnimeSourcesDownloads
|
||||
|
||||
|
||||
class AllAnimeEpisode(TypedDict):
|
||||
episodeString: str
|
||||
sourceUrls: list[AllAnimeSources]
|
||||
notes: str | None
|
||||
56
fastanime/libs/anime_provider/allanime/gql_queries.py
Normal file
@@ -0,0 +1,56 @@
|
||||
ALLANIME_SEARCH_GQL = """
|
||||
query(
|
||||
$search: SearchInput
|
||||
$limit: Int
|
||||
$page: Int
|
||||
$translationType: VaildTranslationTypeEnumType
|
||||
$countryOrigin: VaildCountryOriginEnumType
|
||||
) {
|
||||
shows(
|
||||
search: $search
|
||||
limit: $limit
|
||||
page: $page
|
||||
translationType: $translationType
|
||||
countryOrigin: $countryOrigin
|
||||
) {
|
||||
pageInfo {
|
||||
total
|
||||
}
|
||||
edges {
|
||||
_id
|
||||
name
|
||||
availableEpisodes
|
||||
__typename
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
ALLANIME_EPISODES_GQL = """\
|
||||
query ($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) {
|
||||
episode(
|
||||
showId: $showId
|
||||
translationType: $translationType
|
||||
episodeString: $episodeString
|
||||
) {
|
||||
|
||||
episodeString
|
||||
sourceUrls
|
||||
notes
|
||||
}
|
||||
}"""
|
||||
|
||||
ALLANIME_SHOW_GQL = """
|
||||
query ($showId: String!) {
|
||||
show(
|
||||
_id: $showId
|
||||
) {
|
||||
|
||||
_id
|
||||
name
|
||||
availableEpisodesDetail
|
||||
|
||||
}
|
||||
}
|
||||
"""
|
||||
71
fastanime/libs/anime_provider/allanime/utils.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
|
||||
# Dictionary to map hex values to characters
|
||||
hex_to_char = {
|
||||
"01": "9",
|
||||
"08": "0",
|
||||
"05": "=",
|
||||
"0a": "2",
|
||||
"0b": "3",
|
||||
"0c": "4",
|
||||
"07": "?",
|
||||
"00": "8",
|
||||
"5c": "d",
|
||||
"0f": "7",
|
||||
"5e": "f",
|
||||
"17": "/",
|
||||
"54": "l",
|
||||
"09": "1",
|
||||
"48": "p",
|
||||
"4f": "w",
|
||||
"0e": "6",
|
||||
"5b": "c",
|
||||
"5d": "e",
|
||||
"0d": "5",
|
||||
"53": "k",
|
||||
"1e": "&",
|
||||
"5a": "b",
|
||||
"59": "a",
|
||||
"4a": "r",
|
||||
"4c": "t",
|
||||
"4e": "v",
|
||||
"57": "o",
|
||||
"51": "i",
|
||||
}
|
||||
|
||||
|
||||
def decode_hex_string(hex_string):
|
||||
# Split the hex string into pairs of characters
|
||||
hex_pairs = re.findall("..", hex_string)
|
||||
|
||||
# Decode each hex pair
|
||||
decoded_chars = [hex_to_char.get(pair.lower(), pair) for pair in hex_pairs]
|
||||
|
||||
return "".join(decoded_chars)
|
||||
|
||||
|
||||
def run_fzf(options):
|
||||
"""
|
||||
Run fzf with a list of options and return the selected option.
|
||||
"""
|
||||
# Join the list of options into a single string with newlines
|
||||
options_str = "\n".join(options)
|
||||
|
||||
# Run fzf as a subprocess
|
||||
result = subprocess.run(
|
||||
["fzf"],
|
||||
input=options_str,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
|
||||
# Check if fzf was successful
|
||||
if result.returncode == 0:
|
||||
# Return the selected option
|
||||
return result.stdout.strip()
|
||||
else:
|
||||
# Handle the case where fzf fails or is canceled
|
||||
print("fzf was canceled or failed")
|
||||
return None
|
||||
@@ -1,159 +0,0 @@
|
||||
{
|
||||
"shows": {
|
||||
"pageInfo": {
|
||||
"total": 22279
|
||||
},
|
||||
"edges": [
|
||||
{
|
||||
"_id": "JsbMBPoTsp3RkGfrf",
|
||||
"name": "Sword Art Online: Progressive Movie: Kuraki Yuuyami no Scherzo",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 1,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "YXEMgd5FLhWD2mn8Z",
|
||||
"name": "Sword Art Online: Progressive Movie - Hoshi Naki Yoru no Aria",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 1,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "ALj8oEW6mhWuQ8pHT",
|
||||
"name": "Sword Art Online Movie: Ordinal Scale: Sword Art Offline",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 0,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "DWZeL5vDhEokJQFXR",
|
||||
"name": "Sword Art Offline II",
|
||||
"availableEpisodes": {
|
||||
"sub": 9,
|
||||
"dub": 0,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "fgEBgLfkzEWaCSHAu",
|
||||
"name": "Sword Art Online: Sword Art Offline",
|
||||
"availableEpisodes": {
|
||||
"sub": 9,
|
||||
"dub": 0,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "BvzJ7btmDGBvJCC4P",
|
||||
"name": "Sword Art Online: Extra Edition",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 1,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "4mjsuWL9sAK97zQjL",
|
||||
"name": "Sword Art Offline: Extra Edition",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 0,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "np7xM323v5pH6KY9e",
|
||||
"name": "Sword Art Online: Alicization",
|
||||
"availableEpisodes": {
|
||||
"sub": 25,
|
||||
"dub": 25,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "36bqKyjS3tFybyz7j",
|
||||
"name": "Sword Art Online",
|
||||
"availableEpisodes": {
|
||||
"sub": 25,
|
||||
"dub": 25,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "ierXJrDYNiALG5haP",
|
||||
"name": "Sword Art Online II",
|
||||
"availableEpisodes": {
|
||||
"sub": 26,
|
||||
"dub": 25,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "tkywv9gMqH7mYw4N5",
|
||||
"name": "Sword Art Online: Alicization - War of Underworld Season 2",
|
||||
"availableEpisodes": {
|
||||
"sub": 11,
|
||||
"dub": 11,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "z2stShodurTBWbXgM",
|
||||
"name": "Sword Art Online: Alicization - War of Underworld",
|
||||
"availableEpisodes": {
|
||||
"sub": 14,
|
||||
"dub": 12,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "WwdepehfXq8gpgku9",
|
||||
"name": "Sword Art Online Alternative: Gun Gale Online",
|
||||
"availableEpisodes": {
|
||||
"sub": 13,
|
||||
"dub": 12,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "hjHnDp4NRh9zpcTLJ",
|
||||
"name": "Sword Art Online: Ordinal Scale",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 1,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
},
|
||||
{
|
||||
"_id": "TYTW9KtABBNiMcp5w",
|
||||
"name": "Sword Art Online II: Debriefing",
|
||||
"availableEpisodes": {
|
||||
"sub": 1,
|
||||
"dub": 0,
|
||||
"raw": 0
|
||||
},
|
||||
"__typename": "Show"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
{
|
||||
"episode": {
|
||||
"episodeString": "12",
|
||||
"sourceUrls": [
|
||||
{
|
||||
"sourceUrl": "--175948514e4c4f57175b54575b5307515c050f5c0a0c0f0b0f0c0e590a0c0b5b0a0c0a010a010f080e5e0e0a0f0d0f0a0f0c0e0b0e0f0e5a0e5e0e000e090a000e5e0e010a010e590e010e0f0e0a0a000f0e0e5d0f0e0b010e5e0e0a0b5a0c5a0d0a0c0b0f5d0c010d0a0e5c0b0d0a080f0a0e5e0f0a0e590e0b0b5a0d0d0f090e010f0c0e0a0a5c0c0f0f0c0f0a0a5c0c010e000e590e5e0e000e0b0a0b0b0d0c0f0a5c0c0f0e590e5e0e0d0e5e0f5b0e0f0f0a0e5e0e010e000a080f0a0f5e0f0e0e0b0f0d0f0b0e0c0b5a0d0d0d0b0c0c0a080f0d0f0b0e0c0b5a0a080e0d0e010f080e0b0f0c0b5a0d5e0b0c0b5e0b0c0d5b0d5d0c5e0f080e0d0b0d0e0a0f080e0d0e5a0d0f0f0a0d5e0d5d0c5b0b0e0c590d090b5e0f0b0e0c0c090e590f0b0d5b0d0d0b0f0e5d0e0c0c090e590e5b0e0f0d5d0f0e0e5d0e0a0c090e590f080e0c0e5e0b0b0f090e0c0e5a0e0d0b5a0a0c0a590a0c0f0d0f0a0f0c0e0b0e0f0e5a0e0b0f0c0c5e0e0a0a0c0b5b0a0c0f080e5e0e0a0e0b0e010f0d0f0a0f0c0e0b0e0f0e5a0e5e0e010a0c0a590a0c0e0a0e0f0f0a0e0b0a0c0b5b0a0c0b0c0b0e0b0c0b0a0a5a0b0e0b080a5a0b0e0b090d0a0b0f0b5e0b5b0b0b0b5e0b5b0b0e0b0e0a000b0e0b0e0b0e0d5b0a0c0f5a1e4a5d5e5d4a5d4a05",
|
||||
"priority": 7.7,
|
||||
"sourceName": "Luf-mp4",
|
||||
"type": "iframe",
|
||||
"className": "",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "//vidstreaming.io/load.php?id=MTExOTk3&title=Sword+Art+Online%3A+Alicization&typesub=SUB&sub=&cover=Y292ZXIvc3dvcmQtYXJ0LW9ubGluZS1hbGljaXphdGlvbi5wbmc=",
|
||||
"priority": 4,
|
||||
"sourceName": "Vid-mp4",
|
||||
"type": "iframe",
|
||||
"className": "",
|
||||
"streamerId": "allanime",
|
||||
"downloads": {
|
||||
"sourceName": "Gl",
|
||||
"downloadUrl": "https://embtaku.pro/download?id=MTExOTk3&title=Sword+Art+Online%3A+Alicization&typesub=SUB&sub=&cover=Y292ZXIvc3dvcmQtYXJ0LW9ubGluZS1hbGljaXphdGlvbi5wbmc=&sandbox=allow-forms%20allow-scripts%20allow-same-origin%20allow-downloads"
|
||||
}
|
||||
},
|
||||
{
|
||||
"sourceUrl": "https://streamsb.net/e/kag9w71l9jq0.html",
|
||||
"priority": 5.5,
|
||||
"sourceName": "Ss-Hls",
|
||||
"type": "iframe",
|
||||
"className": "text-danger",
|
||||
"streamerId": "allanime",
|
||||
"downloads": {
|
||||
"sourceName": "StreamSB",
|
||||
"downloadUrl": "https://streamsb.net/d/kag9w71l9jq0.html&sandbox=allow-forms%20allow-scripts%20allow-same-origin%20allow-downloads"
|
||||
}
|
||||
},
|
||||
{
|
||||
"sourceUrl": "--175948514e4c4f57175b54575b5307515c050f5c0a0c0f0b0f0c0e590a0c0b5b0a0c0a010f080e5e0e0a0e0b0e010f0d0a010e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0a010f0d0f0b0e0c0a010b0f0b0c0a0c0a590a0c0f0d0f0a0f0c0e0b0e0f0e5a0e0b0f0c0c5e0e0a0a0c0b5b0a0c0c0a0f0c0e010f0e0e0c0e010f5d0a0c0a590a0c0e0a0e0f0f0a0e0b0a0c0b5b0a0c0b0c0b0e0b0c0b0a0a5a0b0e0b080a5a0b0e0b090d0a0b0f0b5e0b5b0b0b0b5e0b5b0b0e0b0e0a000b0e0b0e0b0e0d5b0a0c0a590a0c0f0a0f0c0e0f0e000f0d0e590e0f0f0a0e5e0e010e000d0a0f5e0f0e0e0b0a0c0b5b0a0c0f0d0f0b0e0c0a0c0a590a0c0e5c0e0b0f5e0a0c0b5b0a0c0e0b0f0e0a5a0a010f080e5e0e0a0e0b0e010f0d0a010e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0a010f0d0f0b0e0c0a010b0f0b0c0a0c0f5a",
|
||||
"priority": 7,
|
||||
"sourceName": "Sak",
|
||||
"type": "iframe",
|
||||
"className": "",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "--504c4c484b0217174c5757544b165e594b4c0c4b485d5d5c164a4b4e4817174e515c5d574b1756480f40750b0a0b4e0d48700e7361015d174b4d5a17090a",
|
||||
"priority": 7.9,
|
||||
"sourceName": "Yt-mp4",
|
||||
"type": "player",
|
||||
"className": "",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "https://mp4upload.com/embed-bayej7b93in0.html",
|
||||
"priority": 4,
|
||||
"sourceName": "Mp4",
|
||||
"type": "iframe",
|
||||
"sandbox": "allow-forms allow-scripts allow-same-origin",
|
||||
"className": "",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "https://ok.ru/videoembed/2731036445330",
|
||||
"priority": 3.5,
|
||||
"sourceName": "Ok",
|
||||
"type": "iframe",
|
||||
"sandbox": "allow-forms allow-scripts allow-same-origin",
|
||||
"className": "text-info",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "--175948514e4c4f57175b54575b5307515c050f5c0a0c0f0b0f0c0e590a0c0b5b0a0c0b0b0b080e0d0b5e0b0a0b0d0d010e0c0b5e0b0c0b080b0f0b0d0e0c0b0a0b0b0b0e0b080b090b0a0b5e0b0f0b080b5e0b5d0e0a0b080e0f0b5e0b0b0e080b0f0b0e0e0c0b0f0b5d0e0f0b0c0e0a0a0e0f590a0e0b0d0e0f0b0d0e080b0a0e0f0e080b0b0b080e0a0b090b0a0b090e0b0b5d0b5e0e0d0b0d0b0e0b0f0b0b0b080e0b0e080b080e0d0b5d0b5d0e0d0b0b0b080e0c0a0e0f590a0e0e5a0e0b0e0a0e5e0e0f0a010b0b0b080e0d0b5e0b0a0b0d0d010e0c0b5e0b0c0b080b0f0b0d0e0c0b0a0b0b0b0e0b080b090b0a0b5e0b0f0b080b5e0b5d0e0a0b080e0f0b5e0b0b0e080b0f0b0e0e0c0b0f0b5d0e0f0b0c0e0a0e080b0e0b0e0b0f0a000e5b0f0e0e090a0e0f590a0e0a590b090b0c0b0e0f0e0a590b0f0b0e0b5d0b0e0f0e0a590b0a0b5d0b0e0f0e0a590a0c0a590a0c0f0d0f0a0f0c0e0b0e0f0e5a0e0b0f0c0c5e0e0a0a0c0b5b0a0c0d090e5e0f5d0a0c0a590a0c0e0a0e0f0f0a0e0b0a0c0b5b0a0c0b0c0b0e0b0c0b0a0a5a0b0e0b080a5a0b0e0b090d0a0b0f0b5e0b5b0b0b0b5e0b5b0b0e0b0e0a000b0e0b0e0b0e0d5b0a0c0a590a0c0f0a0f0c0e0f0e000f0d0e590e0f0f0a0e5e0e010e000d0a0f5e0f0e0e0b0a0c0b5b0a0c0f0d0f0b0e0c0a0c0a590a0c0e5c0e0b0f5e0a0c0b5b0a0c0e0b0f0e0a5a0e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0d010b0f0b0c0d010f0d0f0b0e0c0a0c0f5a",
|
||||
"priority": 8.5,
|
||||
"sourceName": "Default",
|
||||
"type": "iframe",
|
||||
"className": "text-info",
|
||||
"streamerId": "allanime"
|
||||
},
|
||||
{
|
||||
"sourceUrl": "--175948514e4c4f57175b54575b5307515c050f5c0a0c0f0b0f0c0e590a0c0b5b0a0c0a010f0d0e5e0f0a0e0b0f0d0a010e0f0e000e5e0e5a0e0b0a010d0d0e5d0e0f0f0c0e0b0e0a0a0e0c0a0e010e0d0f0b0e5a0e0b0e000f0a0f0d0a010e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0d010b0f0b0c0d010f0d0f0b0e0c0a000e5a0f0e0b0a0a0c0a590a0c0f0d0f0a0f0c0e0b0e0f0e5a0e0b0f0c0c5e0e0a0a0c0b5b0a0c0d0d0e5d0e0f0f0c0e0b0f0e0e010e5e0e000f0a0a0c0a590a0c0e0a0e0f0f0a0e0b0a0c0b5b0a0c0b0c0b0e0b0c0b0a0a5a0b0e0b080a5a0b0e0b090d0a0b0f0b5e0b5b0b0b0b5e0b5b0b0e0b0e0a000b0e0b0e0b0e0d5b0a0c0a590a0c0f0a0f0c0e0f0e000f0d0e590e0f0f0a0e5e0e010e000d0a0f5e0f0e0e0b0a0c0b5b0a0c0f0d0f0b0e0c0a0c0a590a0c0e5c0e0b0f5e0a0c0b5b0a0c0e0b0f0e0a5a0e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0d010b0f0b0c0d010f0d0f0b0e0c0a0c0f5a",
|
||||
"priority": 7.4,
|
||||
"sourceName": "S-mp4",
|
||||
"type": "iframe",
|
||||
"className": "",
|
||||
"streamerId": "allanime",
|
||||
"downloads": {
|
||||
"sourceName": "S-mp4",
|
||||
"downloadUrl": "https://blog.allanime.day/apivtwo/clock/download?id=7d2473746a243c2429756f7263752967686f6b6329556e6774636226426965736b63687275296876317e4b3534357033764e304d5f3f6359373459757364286b7632242a2475727463676b63744f62243c24556e67746376696f6872242a2462677263243c24343634322b36302b363152373f3c333f3c3636283636365c242a24626971686a696762243c727473637b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"sourceUrl": "--175948514e4c4f57175b54575b5307515c050f5c0a0c0f0b0f0c0e590a0c0b5b0a0c0e5d0f0a0f0a0f0e0f0d0b5b0a010a010f0b0f0d0e0b0f0c0f0d0e0d0e590e010f0b0e0a0a000e0d0e010e5a0a010e0b0e5a0e0c0e0b0e0a0a5a0f0f0b5e0e080e590f080e5b0e5b0b0d0e0c0b090f0d0f0f0a000e5d0f0a0e5a0e590a0c0a590a0c0f0d0f0a0f0c0e0b0e0f0e5a0e0b0f0c0c5e0e0a0a0c0b5b0a0c0d0b0f0d0e0b0f0c0f080e5e0e0a0a0c0a590a0c0e0a0e0f0f0a0e0b0a0c0b5b0a0c0b0c0b0e0b0c0b0a0a5a0b0e0b080a5a0b0e0b090d0a0b0f0b5e0b5b0b0b0b5e0b5b0b0e0b0e0a000b0e0b0e0b0e0d5b0a0c0a590a0c0f0a0f0c0e0f0e000f0d0e590e0f0f0a0e5e0e010e000d0a0f5e0f0e0e0b0a0c0b5b0a0c0f0d0f0b0e0c0a0c0a590a0c0e5c0e0b0f5e0a0c0b5b0a0c0e0b0f0e0a5a0e000f0e0b090f5d0c5a0b0d0b0c0b0d0f080b0b0f0e0c5d0b080c5c0d5e0b5e0e0b0d010b0f0b0c0d010f0d0f0b0e0c0a0c0f5a",
|
||||
"priority": 1,
|
||||
"sourceName": "Uv-mp4",
|
||||
"type": "iframe",
|
||||
"className": "",
|
||||
"streamerId": "allanime"
|
||||
}
|
||||
],
|
||||
"notes": null
|
||||
}
|
||||
}
|
||||