Skip to content

Commit

Permalink
- updated to new eaf_base_api v2
Browse files Browse the repository at this point in the history
- added error if video is still processing
- fixed tests
- type hinting
  • Loading branch information
EchterAlsFake committed Jan 2, 2025
1 parent 8de6b80 commit a4d2fd7
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 170 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
custom: "https://paypal.me/EchterAlsFake"
6 changes: 5 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Spankbang API test

on: [push, pull_request]
on:
push:
pull_request:
schedule:
- cron: '0 0 * * 0' # Runs every Sunday at 00:00 UTC

jobs:
build:
Expand Down
4 changes: 3 additions & 1 deletion README/Changelog.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# 1.0
- initial project
- initial project

# 1.1
128 changes: 0 additions & 128 deletions README/Documentation.md

This file was deleted.

5 changes: 2 additions & 3 deletions spankbang_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
__all__ = ['Client', "Search", "Quality", "Callback", "Video", "consts", "default", "threaded", "FFMPEG",
"legacy_download"]
__all__ = ['Client', "Search", "Callback", "Video", "consts"]

from spankbang_api.spankbang_api import Client, Search, Quality, Callback, Video, default, threaded, FFMPEG, legacy_download
from spankbang_api.spankbang_api import Client, Search, Callback, Video
from spankbang_api.modules import consts
2 changes: 1 addition & 1 deletion spankbang_api/modules/consts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import re

headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Referer": "https://spankbang.com",
}

Expand All @@ -20,3 +19,4 @@
REGEX_VIDEO_RATING = re.compile(r'<span class="rate">(.*?)</span>')
REGEX_VIDEO_AUTHOR = re.compile(r'<span class="name">(.*?)</span>')
REGEX_VIDEO_LENGTH = re.compile(r'<span class="i-length">(.*?)</span>')
REGEX_VIDEO_PROCESSING = re.compile(r'<div class="warning_process">')
3 changes: 3 additions & 0 deletions spankbang_api/modules/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class VideoIsProcessing(Exception):
def __init__(self):
self.msg = "The video is still processing on spankbang's servers!"
79 changes: 44 additions & 35 deletions spankbang_api/spankbang_api.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,64 @@
import json
import html
import logging
import os.path

import requests
from base_api.base import Core, setup_api
from base_api.modules.download import legacy_download, threaded, default, FFMPEG
from base_api.modules.progress_bars import Callback
from base_api.modules.quality import Quality
from typing import Literal
from bs4 import BeautifulSoup
from base_api.base import BaseCore
from functools import cached_property
from pathlib import Path

from typing import Literal
from base_api.modules import consts as bs_consts
from base_api.modules.progress_bars import Callback

try:
from modules.consts import *
from modules.errors import *

except (ImportError, ModuleNotFoundError):
from .modules.consts import *
from .modules.errors import *


base_qualities = ["240p", "320p", "480p", "720p", "1080p", "4k"]
bs_consts.HEADERS = headers
core = BaseCore()
logging.basicConfig(format='%(name)s %(levelname)s %(asctime)s %(message)s', datefmt='%I:%M:%S %p')
logger = logging.getLogger("SPANKBANG API")
logger.setLevel(logging.DEBUG)

def disable_logging():
logger.setLevel(logging.CRITICAL)


class Video:
def __init__(self, url):
self.url = url # Needed for Porn Fetch
self.html_content = Core().get_content(url, headers=headers, cookies=cookies).decode("utf-8")
self.html_content = core.fetch(url, cookies=cookies)

if '<div class="warning_process">' in self.html_content:
raise VideoIsProcessing

self.soup = BeautifulSoup(self.html_content, "lxml")
self.extract_script_2()
self.extract_script_1()

def extract_script_1(self):
"""This extracts the script with the basic video information"""
main_container = self.soup.find("main", class_="main-container")
script_tag = main_container.find('script', {"type": "application/ld+json"})
self.json_tags = json.loads(html.unescape(script_tag.string))
script_tag = self.soup.find_all('script', {"type": "application/ld+json"})

for script in script_tag:
if "thumbnailUrl" in script.text:
text = html.unescape(script.text)
text = text.replace("\t", " ")
self.json_tags = json.loads(html.unescape(text))
return

raise "No script was found, please report this immediately with the URL you used"

def extract_script_2(self):
"""This extracts the script with the m3u8 URLs which contain the segments used for downloading"""
main_container = self.soup.find('main', class_='main-container')
script_tag = main_container.find('script', {'type': 'text/javascript'})
stream_data_js = re.search(r'var stream_data = ({.*?});', script_tag.text, re.DOTALL).group(1)
stream_data_js = re.search(r'var stream_data = ({.*?});', script_tag.text.replace("\t", " "), re.DOTALL).group(1)
m3u8_pattern = re.compile(r"'m3u8': \['(https://[^']+master.m3u8[^']*)'\]")
resolution_pattern = re.compile(r"'(240p|320p|480p|720p|1080p|4k)': \['(https://[^']+.mp4[^']*)'\]")

Expand Down Expand Up @@ -93,6 +112,7 @@ def author(self) -> str:
@cached_property
def rating(self) -> str:
"""Returns the rating of the video"""
print(self.html_content)
return REGEX_VIDEO_RATING.search(self.html_content).group(1)

@cached_property
Expand Down Expand Up @@ -127,39 +147,31 @@ def video_qualities(self) -> list:

def get_segments(self, quality) -> list:
"""Returns a list of segments by a given quality for HLS streaming"""
quality = Core().fix_quality(quality)
segments = Core().get_segments(quality, base_qualities=base_qualities, m3u8_base_url=self.m3u8_master,
seperator="-", source="spankbang")

fixed_segments = []
return core.get_segments(quality=quality, m3u8_url_master=self.m3u8_master)

for seg in segments:
fixed_segments.append(str(seg).split(".mp4.urlset/")[1])
def download(self, quality: str, downloader: str = "threaded", path="./" ,callback=Callback.text_progress_bar,
no_title=False, use_hls=True):

return fixed_segments

def download(self, path, quality, downloader="threaded", callback=Callback.text_progress_bar, no_title=False, use_hls=True):
quality = Core().fix_quality(quality)
if no_title is False:
path = Path(str(path) + str(Core().strip_title(self.title) + ".mp4"))
path = os.path.join(path, core.strip_title(self.title) + ".mp4")

if use_hls:
Core().download(video=self, quality=quality, path=path, callback=callback, downloader=downloader)
core.download(video=self, quality=quality, path=path, callback=callback, downloader=downloader)

else:
cdn_urls = self.direct_download_urls
quals = self.video_qualities
quality_url_map = {qual: url for qual, url in zip(quals, cdn_urls)}

quality_map = {
Quality.BEST: max(quals, key=lambda x: int(x)),
Quality.HALF: sorted(quals, key=lambda x: int(x))[len(quals) // 2],
Quality.WORST: min(quals, key=lambda x: int(x))
"best": max(quals, key=lambda x: int(x)),
"half": sorted(quals, key=lambda x: int(x))[len(quals) // 2],
"worst": min(quals, key=lambda x: int(x))
}

selected_quality = quality_map[quality]
download_url = quality_url_map[selected_quality]
legacy_download(stream=True, url=download_url, path=path, callback=callback)
core.legacy_download(stream=True, url=download_url, path=path, callback=callback)


class Search:
Expand All @@ -183,15 +195,12 @@ def __init__(self, query, trending : bool = False, new: bool = False, popular: b

else:
""

if new:
new = "new"

else:

self.html_content = Core().get_content(url=f"https://www.spankbang.com/s/{query}/?o={trending}", headers=headers,
cookies=cookies).decode("utf-8")

self.html_content = core.fetch(url=f"https://www.spankbang.com/s/{query}/?o={trending}", cookies=cookies)


class Client:
Expand Down
2 changes: 1 addition & 1 deletion spankbang_api/tests/test_video.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from spankbang_api.spankbang_api import Video

url = "https://spankbang.com/9ieve/video/perfect+blonde+pounded"
url = "https://de.spankbang.com/9lw26/video/puerto+rican+venezuelan+3"
try:
video = Video(url)

Expand Down

0 comments on commit a4d2fd7

Please sign in to comment.