| import os |
| from urllib.request import urlopen, Request |
| from urllib.error import URLError |
| from bs4 import BeautifulSoup |
| |
| SPEC_DIR = os.path.join( |
| os.path.dirname(os.path.dirname(os.path.abspath(__file__))), |
| "specifications", |
| ) |
| |
| # List of specifications to download |
| SPECS = [ |
| { |
| "name": "BAP_v1.0.2", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/BAP_v1.0.2/out/en/index-en.html", |
| }, |
| { |
| "name": "CAP_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/CAP_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "TMAP_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/TMAP_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "HAP_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/HAP_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "PBP_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/PBP_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "MCP_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/28982-MCP-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "CCP_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/26587-CCP-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "MICP_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/21264-MICP-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "VCP_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/76878-VCP-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "ASCS_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/ASCS_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "PACS_v1.0.2", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/PACS_v1.0.2/out/en/index-en.html", |
| }, |
| { |
| "name": "CSIS_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/28085-CSIS-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "CSIP_v1.0", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/27407-CSIP-html5/out/en/index-en.html", |
| }, |
| { |
| "name": "BASS_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/BASS_v1.0.1/out/en/index-en.html", |
| }, |
| { |
| "name": "AICS_v1.0.1", |
| "url": "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/AICS_v1.0.1/out/en/index-en.html", |
| }, |
| ] |
| |
| def download_spec(name, url): |
| print(f"Downloading {name} from {url}...") |
| headers = {'User-Agent': 'Mozilla/5.0'} |
| try: |
| req = Request(url, headers=headers) |
| with urlopen(req, timeout=30) as response: |
| html_content = response.read() |
| |
| # Create spec dir if not exists |
| os.makedirs(SPEC_DIR, exist_ok=True) |
| |
| # Save HTML |
| html_path = os.path.join(SPEC_DIR, f"{name}.html") |
| with open(html_path, 'wb') as f: |
| f.write(html_content) |
| print(f"Saved HTML to {html_path}") |
| |
| # Save Text/Markdown for searching |
| soup = BeautifulSoup(html_content, 'html.parser') |
| text_content = soup.get_text(separator='\n', strip=True) |
| |
| md_path = os.path.join(SPEC_DIR, f"{name}.md") |
| with open(md_path, 'w', encoding='utf-8') as f: |
| f.write(text_content) |
| print(f"Saved Markdown to {md_path}") |
| |
| except URLError as e: |
| print(f"Error downloading {name}: {e}") |
| except Exception as e: |
| print(f"An error occurred: {e}") |
| |
| def main(): |
| for spec in SPECS: |
| download_spec(spec["name"], spec["url"]) |
| |
| if __name__ == "__main__": |
| main() |