[
  {
    "path": ".gitignore",
    "content": "hosts"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Konnyaku\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MicrosoftHostsPicker.py",
    "content": "import concurrent.futures\nfrom typing import List, Tuple\nfrom ping3 import ping\n\n\ndef ping_ip(ip: str, attempts: int = 3, timeout: float = 1.0) -> float:\n    total_time = 0.0\n    for _ in range(attempts):\n        ping_time = ping(ip, timeout=timeout, unit='ms')\n        if ping_time is None:\n            return float('inf')\n        total_time += ping_time\n    return total_time / attempts\n\n\ndef process_ip_list(file_path: str) -> Tuple[str, float]:\n    best_ip = ''\n    best_time = float('inf')\n    with open(file_path, 'r') as file:\n        for ip in file:\n            ip = ip.strip()\n            avg_time = ping_ip(ip)\n            if avg_time < best_time:\n                best_ip = ip\n                best_time = avg_time\n    return best_ip, best_time\n\n\ndef write_hosts_section(hosts_file, title: str, ip: str, domains: List[str]):\n    hosts_file.write(f'# {title}\\n')\n    for domain in domains:\n        hosts_file.write(f'{ip} {domain}\\n')\n    hosts_file.write('\\n')\n\n\ndef main():\n    ip_files = {\n        'Microsoft_Account': './data/Microsoft_Account.txt',\n        'Xbox_Live_CDN_1': './data/Xbox_Live_CDN_1.txt',\n        'Xbox_Live_CDN_2': './data/Xbox_Live_CDN_2.txt',\n        'Xbox_Cloud_Sync': './data/Xbox_Cloud_Sync.txt',\n        'Office_CDN': './data/Office_CDN.txt',\n        'Microsoft_Store_Images': './data/Microsoft_Store_Images.txt',\n        'Microsoft_Store_Pages': './data/Microsoft_Store_Pages.txt',\n        'Microsoft_Games_Download': './data/Microsoft_Games_Download.txt',\n        'Windows_Update': './data/Windows_Update.txt',\n    }\n\n    with concurrent.futures.ThreadPoolExecutor() as executor:\n        future_to_file = {executor.submit(process_ip_list, file_path): file_name \n                          for file_name, file_path in ip_files.items()}\n        \n        results = {}\n        for future in concurrent.futures.as_completed(future_to_file):\n            file_name = future_to_file[future]\n            ip, time = future.result()\n            results[file_name] = ip\n            print(f\"{file_name}: {ip} ({time:.2f}ms)\")\n\n    with open(\"hosts\", 'w') as hosts:\n        # OneDrive Hosts beta\n        write_hosts_section(hosts, 'OneDrive (Beta, only for China)', '',\n                            ['134.170.108.26 onedrive.live.com',\n                             '134.170.109.48 skyapi.onedrive.live.com'])\n\n        # Microsoft Login Hosts\n        write_hosts_section(hosts, 'Microsoft Login', '13.107.42.22',\n                            ['logincdn.msauth.net', 'login.live.com',\n                             'acctcdn.msauth.net', 'account.live.com'])\n\n        write_hosts_section(hosts, 'Microsoft Account', results['Microsoft_Account'],\n                            ['account.microsoft.com'])\n\n        # Xbox Live CDN\n        xbox_live_cdn_domains = [\n            'gameclipscontent-d2009.xboxlive.com', 'images-eds.xboxlive.com',\n            'xbl-smooth.xboxlive.com', 'titlehub.xboxlive.com', 'compass.xboxlive.com',\n            'xnotify.xboxlive.com', 'activityhub.xboxlive.com', 'xboxcare.xboxlive.com',\n            'images-eds-ssl.xboxlive.com', 'rta.xboxlive.com', 'peoplehub.xboxlive.com',\n            'editorial.xboxlive.com'\n        ]\n        write_hosts_section(hosts, 'Xbox Live CDN', results['Xbox_Live_CDN_1'], xbox_live_cdn_domains)\n\n        write_hosts_section(hosts, 'Xbox Cloud Sync', results['Xbox_Cloud_Sync'],\n                            ['titlestorage.xboxlive.com'])\n\n        write_hosts_section(hosts, 'Office CDN', results['Office_CDN'],\n                            ['officecdn.microsoft.com'])\n\n        write_hosts_section(hosts, 'Microsoft Store Images', results['Microsoft_Store_Images'],\n                            ['store-images.s-microsoft.com'])\n\n        write_hosts_section(hosts, 'Microsoft Store Pages', results['Microsoft_Store_Pages'],\n                            ['storeedgefd.dsx.mp.microsoft.com'])\n\n        write_hosts_section(hosts, 'Microsoft Games Download', results['Microsoft_Games_Download'],\n                            ['xvcf1.xboxlive.com', 'xvcf2.xboxlive.com'])\n\n        write_hosts_section(hosts, 'Windows Update', results['Windows_Update'],\n                            ['tlu.dl.delivery.mp.microsoft.com', 'dl.delivery.mp.microsoft.com',\n                             'assets1.xboxlive.cn', 'assets2.xboxlive.cn'])\n\n    print('All done.')\n    print('The output Hosts file is in the \"hosts\" in the same directory as \"MicrosoftHostsPicker.py\".')\n    print('Please select the hosts you need to add to your system.')\n    input('Press Enter to exit...')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "README.md",
    "content": "# Microsoft Hosts Picker - M$💊\n\nA lightweight Python script to help you select the fastest IP addresses for Microsoft services.\n\n## Why This Tool?\n\nIn certain regions, Microsoft services may not function optimally due to DNS resolving to suboptimal IP addresses. This script aims to address that issue by finding the most responsive IPs for various Microsoft services.\n\n## Getting Started\n\n1. Install dependencies:\n\n```sh\npip install -r requirements.txt\n```\n\n2. Download the latest [ZIP](https://github.com/ButaiKirin/MicrosoftHostsPicker/archive/refs/heads/main.zip) from this repository.\n\n3. Extract the contents to your preferred location.\n\n4. Run the script:\n\n```sh\npython MicrosoftHostsPicker.py\n```\n\n## How It Works\n\nThe script automatically selects the best IP addresses for various Microsoft services. Results are saved in a \"hosts\" file in the same directory as \"MicrosoftHostsPicker.py\".\n\n## Usage Tips\n\n- Only replace the problematic IP addresses in your system's hosts file.\n- Avoid overwriting all entries, as this may cause unintended issues.\n- Some services (e.g., Office Download and Windows Update) use global CDN nodes and may not require manual configuration unless your DNS is resolving incorrectly.\n\n\nEnjoy faster and more reliable access to Microsoft services!\n"
  },
  {
    "path": "data/Microsoft_Account.txt",
    "content": "23.192.120.51\r\n23.205.249.96\r\n23.43.191.223\r\n184.26.37.234\r\n184.31.41.99\r\n104.126.22.240\r\n23.198.123.197\r\n96.16.0.12\r\n104.102.111.71\r\n104.86.21.130\r\n23.46.242.180\r\n23.14.236.26\r\n104.84.165.78\r\n104.127.2.69\r\n184.25.94.23\r\n2.18.130.30\r\n23.42.218.109\r\n23.42.230.221\r\n23.15.137.62\r\n23.15.106.157\r\n104.93.164.17\r\n23.34.191.223\r\n104.124.19.121\r\n104.74.192.50\r\n23.37.44.103\r\n23.66.151.205\r\n118.215.176.239\r\n184.51.248.236\r\n223.119.244.240\r\n104.120.150.36\r\n173.223.149.80\r\n23.13.246.239\r\n2.17.4.205\r\n23.51.125.60\r\n223.119.207.61\r\n104.95.186.125\r\n96.16.86.245\r\n104.96.8.210\r\n23.65.243.236\r\n23.201.83.137\r\n23.35.168.21\r\n104.66.90.173\r\n23.204.228.173\r\n184.85.152.224\r\n104.116.15.193\r\n184.26.249.105\r\n95.101.198.93\r\n23.6.111.223\r\n104.96.144.219\r\n23.77.13.252\r\n23.50.97.161\r\n23.53.145.30\r\n23.218.131.142\r\n95.100.117.56\r\n23.218.23.32\r\n104.100.19.155\r\n23.4.207.194\r\n2.20.193.168\r\n23.199.129.30\r\n2.19.148.42\r\n23.49.9.213\r\n104.81.220.182\r\n104.75.192.24\r\n23.77.146.110\r\n23.207.137.12\r\n2.19.127.199\r\n88.221.237.163\r\n104.104.169.37\r\n104.88.39.246\r\n104.116.168.170\r\n23.38.253.160\r\n104.122.121.144\r\n23.209.242.51\r\n23.36.213.82\r\n23.15.255.17\r\n23.72.19.230\r\n104.85.76.115\r\n23.13.83.223\r\n104.109.57.10\r\n23.35.91.151\r\n104.97.155.160\r\n104.90.85.49\r\n104.119.206.226\r\n104.85.140.106\r\n23.35.13.41\r\n184.26.196.167\r\n118.215.85.104\r\n23.7.106.187\r\n23.2.136.202\r\n104.83.146.35\r\n104.75.61.196\r\n23.2.55.120\r\n23.210.143.25\r\n104.97.207.211\r\n23.195.220.114\r\n104.120.228.69\r\n23.8.183.228\r\n92.123.47.82\r\n173.223.58.231\r\n104.78.249.230\r\n23.217.234.233\r\n104.98.7.91\r\n173.222.155.126\r\n23.14.168.89\r\n23.202.136.38\r\n184.26.0.215\r\n23.8.221.97\r\n104.112.0.182\r\n96.16.126.74\r\n104.113.184.139\r\n104.84.243.74\r\n23.35.127.223\r\n23.59.206.229\r\n23.47.24.163\r\n23.42.123.61\r\n23.35.45.202\r\n184.87.68.192\r\n104.126.217.217\r\n104.118.45.84\r\n23.78.170.154\r\n23.193.159.124\r\n23.49.121.173\r\n23.202.111.223\r\n104.78.113.145\r\n104.77.224.7\r\n104.98.202.21\r\n104.120.221.30\r\n23.61.73.164\r\n2.18.39.212\r\n23.46.143.223\r\n23.3.238.49"
  },
  {
    "path": "data/Microsoft_Games_Download.txt",
    "content": "23.210.215.81\r\n23.50.57.116\r\n23.210.215.105\r\n23.44.4.234\r\n23.196.11.62\r\n208.185.115.97\r\n92.123.77.74\r\n23.215.190.208\r\n104.117.183.193\r\n2.22.48.27\r\n23.50.49.180\r\n173.222.108.200\r\n173.223.11.144\r\n23.32.241.81\r\n184.25.56.148\r\n23.223.199.137\r\n2.22.119.32\r\n23.40.41.28\r\n88.221.135.74\r\n23.50.49.179\r\n184.50.113.130\r\n69.192.4.67\r\n23.218.80.168\r\n23.32.56.137\r\n96.17.167.19\r\n23.223.57.40\r\n23.220.167.74\r\n104.99.238.42\r\n23.45.112.202\r\n23.0.174.187\r\n2.21.71.90\r\n23.220.167.8\r\n184.84.150.17\r\n92.123.195.99\r\n104.98.3.11\r\n23.45.180.184\r\n23.45.112.200\r\n23.34.247.80\r\n96.17.167.17\r\n23.202.35.75\r\n2.21.34.34\r\n23.45.180.154\r\n23.194.212.97\r\n23.46.16.223\r\n23.40.196.49\r\n23.59.190.139\r\n23.211.108.27\r\n23.40.41.15\r\n184.28.50.147\r\n23.63.245.40\r\n69.192.4.89\r\n104.86.110.242\r\n23.63.245.43\r\n184.28.50.136\r\n2.23.167.98\r\n124.40.41.84\r\n2.23.167.59\r\n23.50.49.186\r\n23.10.252.26\r\n104.86.110.216\r\n23.206.195.56\r\n104.91.69.83\r\n23.32.56.138\r\n139.175.236.106\r\n23.1.237.225\r\n23.205.154.25\r\n104.91.69.11\r\n184.150.58.161\r\n23.205.154.19\r\n23.223.197.16\r\n184.27.123.138\r\n23.215.177.26\r\n23.32.3.106\r\n23.223.57.75\r\n23.76.153.202\r\n23.205.154.27\r\n92.123.77.80\r\n23.219.39.98\r\n23.32.3.122\r\n23.32.238.170\r\n23.205.154.18"
  },
  {
    "path": "data/Microsoft_Login.txt",
    "content": "117.28.245.88\r\n152.199.40.6\r\n13.107.213.49\r\n13.107.246.49\r\n13.107.246.69\r\n13.107.246.38\r\n192.229.211.199\r\n13.107.246.46\r\n192.229.221.185\r\n13.107.246.39\r\n13.107.246.51\r\n13.107.246.47\r\n13.107.246.70\r\n13.107.246.71\r\n13.107.213.36"
  },
  {
    "path": "data/Microsoft_Store_Images.txt",
    "content": "184.25.249.141\r\n23.45.61.216\r\n23.200.153.227\r\n23.45.57.216\r\n23.197.185.151\r\n184.50.93.123\r\n23.44.1.197\r\n23.50.125.135\r\n173.222.235.222\r\n23.57.115.64\r\n88.221.18.124\r\n104.123.205.191\r\n23.2.77.195\r\n23.211.32.13\r\n23.41.209.151\r\n23.201.37.140\r\n184.26.130.76\r\n23.208.65.246\r\n23.199.77.227\r\n184.86.217.156\r\n104.75.165.226\r\n23.60.109.151\r\n96.7.213.143\r\n104.109.241.150\r\n184.27.29.252\r\n23.211.229.236\r\n23.40.37.156\r\n173.222.182.76\r\n104.85.1.135\r\n23.45.134.201\r\n184.30.21.144\r\n96.16.89.156"
  },
  {
    "path": "data/Microsoft_Store_Pages.txt",
    "content": "117.21.204.223\r\n221.230.146.211\r\n60.210.8.160\r\n223.111.105.38\r\n27.148.138.181\r\n182.247.226.216\r\n221.194.157.13\r\n122.224.46.180\r\n23.40.45.233\r\n23.1.246.92\r\n23.55.249.219\r\n104.109.241.212\r\n23.78.218.53\r\n23.51.209.146\r\n23.53.253.100\r\n2.18.233.45\r\n96.16.89.232\r\n104.117.73.212\r\n23.60.109.206\r\n23.45.199.202\r\n96.7.233.218\r\n23.57.113.5\r\n23.48.230.59\r\n23.40.121.232\r\n23.11.189.139\r\n104.85.1.198"
  },
  {
    "path": "data/Office_CDN.txt",
    "content": "112.65.118.99\r\n218.2.0.234\r\n49.79.237.57\r\n221.194.154.121\r\n202.109.143.67\r\n116.207.139.42\r\n49.79.237.56\r\n124.205.198.173\r\n183.134.26.77\r\n122.5.60.150\r\n139.215.144.19\r\n118.182.230.37\r\n49.79.237.43\r\n58.20.137.220\r\n118.182.230.40\r\n218.2.0.236\r\n122.224.44.186\r\n123.244.38.41\r\n49.79.237.48\r\n49.79.237.58\r\n49.79.237.51\r\n118.182.230.36\r\n42.49.13.28\r\n223.111.179.37\r\n117.34.43.54\r\n219.147.109.13\r\n106.117.241.120\r\n118.182.230.55\r\n221.230.144.165\r\n180.97.232.184\r\n49.79.237.45\r\n180.97.232.89\r\n121.22.230.85\r\n180.97.232.186\r\n106.117.241.119\r\n49.79.237.55\r\n124.165.125.32\r\n23.40.44.59\r\n223.111.179.40\r\n117.34.43.53\r\n36.156.46.28\r\n106.117.241.68\r\n36.156.46.30\r\n1.180.21.197\r\n180.97.232.185\r\n120.52.72.63\r\n96.17.188.60\r\n23.200.152.67\r\n23.35.180.91\r\n23.1.244.73\r\n104.119.104.60\r\n23.45.196.159\r\n23.55.248.61\r\n23.38.114.109\r\n104.85.4.56\r\n2.18.232.120\r\n23.48.228.67\r\n23.40.120.59\r\n23.51.208.92\r\n104.109.240.60\r\n96.7.212.56\r\n104.124.16.42\r\n123.184.153.76\r\n120.201.104.55\r\n120.52.72.64\r\n219.147.98.24\r\n111.19.137.73\r\n113.200.41.34\r\n115.238.137.179\r\n183.240.1.59\r\n119.36.245.185\r\n183.134.235.35\r\n36.150.13.157\r\n122.189.224.34\r\n27.148.137.150\r\n183.249.20.48\r\n36.248.21.14\r\n36.150.13.134\r\n112.132.226.44\r\n183.47.233.58\r\n183.134.26.61\r\n218.98.50.41\r\n139.215.146.75\r\n222.220.214.83\r\n120.198.141.120\r\n117.156.133.199\r\n120.52.72.55\r\n221.233.240.57\r\n115.85.200.170\r\n183.134.235.20\r\n120.220.20.115\r\n120.52.72.58\r\n180.97.232.94\r\n183.249.20.62\r\n112.132.226.43\r\n123.184.153.78\r\n184.86.92.59\r\n120.52.72.102\r\n118.182.230.169\r\n101.106.15.15\r\n1.180.18.42\r\n60.163.162.45\r\n119.84.174.124\r\n36.150.13.139\r\n122.189.224.35\r\n119.84.174.121\r\n42.49.13.29\r\n182.106.151.74\r\n36.150.13.133\r\n112.132.226.57\r\n183.134.235.34\r\n36.150.13.135\r\n123.184.153.73\r\n218.60.121.83\r\n115.238.202.204\r\n221.178.101.50\r\n125.44.162.62\r\n118.121.192.156\r\n120.198.141.116\r\n118.182.230.152\r\n221.178.101.53\r\n121.22.230.27\r\n123.184.153.71\r\n120.201.104.56\r\n139.215.145.221\r\n113.96.163.17\r\n120.226.7.37\r\n119.84.174.122\r\n221.178.101.48\r\n113.200.41.36\r\n223.111.173.69\r\n118.182.230.137\r\n60.165.117.51\r\n117.156.133.197\r\n115.85.200.167"
  },
  {
    "path": "data/OneNote.txt",
    "content": "52.109.2.48\r\n52.109.92.45\r\n52.109.132.46\r\n52.109.28.36\r\n52.109.88.148\r\n52.109.44.33\r\n52.109.44.31\r\n52.109.48.27\r\n52.109.56.36\r\n52.109.112.84\r\n52.109.2.57\r\n52.109.116.45\r\n52.109.112.50\r\n52.109.32.34\r\n52.118.59.43\r\n52.109.44.33\r\n52.109.44.31\r\n52.109.48.27\r\n52.109.64.26\r\n52.109.56.57\r\n52.109.0.48\r\n52.109.2.57\r\n52.109.52.56\r\n52.109.12.15\r\n52.109.96.24\r\n52.109.12.99\r\n52.109.88.196\r\n52.109.132.71"
  },
  {
    "path": "data/Windows_Update.txt",
    "content": "182.101.26.4\r\n182.101.26.120\r\n182.108.43.1\r\n183.232.171.123\r\n222.186.49.117\r\n182.101.26.2\r\n118.180.61.1\r\n119.36.226.247\r\n182.101.26.121\r\n182.84.202.1\r\n58.216.107.92\r\n113.7.202.1\r\n222.213.21.1\r\n153.35.101.35\r\n1.180.27.251\r\n118.112.23.229\r\n112.13.208.244\r\n222.138.71.115\r\n182.101.26.3\r\n175.6.13.246\r\n23.32.56.152\r\n1.198.5.228\r\n42.202.37.2\r\n123.245.253.229\r\n121.12.122.114\r\n60.167.222.69\r\n8.241.177.254\r\n182.150.10.39\r\n150.138.231.145\r\n61.133.64.1\r\n221.228.67.211\r\n106.120.158.105\r\n123.161.59.231\r\n117.169.12.80\r\n58.49.136.3\r\n221.195.206.1\r\n220.194.79.74\r\n122.246.3.213\r\n58.49.157.119\r\n59.63.237.196\r\n106.7.64.1\r\n221.228.219.190\r\n117.34.50.92\r\n58.216.106.229\r\n219.146.241.121\r\n182.108.43.2\r\n58.49.180.1\r\n111.29.52.251\r\n221.228.67.151\r\n122.227.201.1\r\n221.228.67.207\r\n182.101.26.6\r\n180.96.0.13\r\n42.202.37.5\r\n175.6.153.1\r\n220.194.87.114\r\n61.240.218.1\r\n104.91.69.89\r\n13.107.4.50\r\n205.185.216.10\r\n104.91.69.98\r\n205.185.216.42\r\n121.254.136.59\r\n139.175.236.56\r\n184.150.58.154\r\n8.241.175.254\r\n23.216.159.9\r\n104.91.69.56\r\n23.32.238.235\r\n23.205.154.24\r\n112.16.236.207\r\n8.255.130.126\r\n23.205.154.9\r\n93.184.221.240\r\n23.216.159.35\r\n125.89.168.1\r\n8.241.154.254\r\n124.229.62.1"
  },
  {
    "path": "data/Xbox_Cloud_Sync.txt",
    "content": "13.107.42.15\r\n52.252.254.179\r\n52.156.94.70\r\n13.107.3.1\r\n13.107.6.1\r\n13.107.7.1\r\n13.107.5.2\r\n13.107.47.1\r\n13.107.46.2\r\n13.107.49.1\r\n13.107.51.50\r\n131.253.21.2\r\n131.253.33.1\r\n150.171.32.6\r\n150.171.40.6\r\n52.113.194.1\r\n52.113.196.1\r\n52.113.197.6\r\n13.107.52.1"
  },
  {
    "path": "data/Xbox_Live_CDN_1.txt",
    "content": "184.50.87.35\r\n184.50.87.32\r\n104.100.95.19\r\n2.21.71.177\r\n63.217.233.11\r\n104.100.95.17\r\n23.202.34.235\r\n23.215.102.57\r\n23.67.53.41\r\n23.223.57.144\r\n184.50.26.66\r\n23.54.162.153\r\n104.109.128.112\r\n23.40.207.40\r\n23.40.41.27\r\n23.54.162.208\r\n88.221.134.216\r\n23.32.237.51\r\n23.223.54.163\r\n23.47.190.137\r\n184.26.91.47\r\n104.99.238.113\r\n104.98.114.24\r\n104.109.128.115\r\n23.59.190.187\r\n23.215.100.229\r\n23.35.98.24\r\n23.55.220.137\r\n95.101.34.81\r\n23.194.213.139\r\n23.61.195.26\r\n23.220.167.105\r\n172.232.16.145\r\n184.50.26.64\r\n23.40.197.194\r\n23.56.237.205\r\n92.122.244.11\r\n184.28.75.160\r\n23.223.57.161\r\n23.192.47.161\r\n104.91.69.16\r\n63.217.233.16\r\n23.220.167.123\r\n23.55.220.161\r\n104.99.238.65\r\n88.221.134.179\r\n92.123.245.128\r\n23.50.129.82\r\n184.28.223.16\r\n23.45.112.161\r\n184.86.250.24\r\n96.17.102.33\r\n96.7.128.75\r\n23.196.47.89\r\n139.175.87.19\r\n23.204.146.203\r\n203.74.140.202\r\n23.32.236.59\r\n121.254.136.48\r\n119.207.64.136\r\n184.28.223.96\r\n23.32.236.106\r\n23.196.47.99\r\n23.204.146.137\r\n23.52.0.185\r\n2.16.186.26\r\n92.123.77.32\r\n184.28.218.131\r\n23.35.111.74\r\n23.67.53.137\r\n23.33.33.178\r\n23.32.236.32\r\n184.150.58.152"
  },
  {
    "path": "data/Xbox_Live_CDN_2.txt",
    "content": "173.222.180.12\r\n23.40.180.10\r\n23.40.44.10\r\n23.40.1.117\r\n23.3.84.10\r\n104.85.244.12\r\n104.95.252.10\r\n23.195.254.33\r\n23.205.36.9\r\n23.36.176.11\r\n96.16.108.10\r\n23.51.208.11\r\n184.27.212.18\r\n104.74.20.10\r\n104.75.164.10\r\n104.91.76.10\r\n23.200.148.10\r\n23.207.172.10\r\n23.56.0.33\r\n95.100.144.34\r\n23.0.246.37\r\n23.204.248.59\r\n104.118.220.22\r\n184.27.28.11\r\n104.123.204.11\r\n23.47.120.15\r\n104.102.28.11\r\n23.53.252.13\r\n23.59.156.11\r\n23.48.228.10\r\n23.193.52.13\r\n23.57.112.17\r\n23.55.248.10\r\n23.40.120.10\r\n223.119.202.32\r\n23.1.244.11\r\n104.85.0.10\r\n23.78.216.11\r\n96.16.88.10\r\n23.72.44.9\r\n104.124.45.99\r\n2.18.232.16\r\n23.45.132.11\r\n23.45.196.54\r\n173.223.108.10"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <link rel=\"icon\" type=\"image/webp\" href=\"favicon.webp\">\n    <title>Microsoft Hosts Picker</title>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <link href=\"https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&family=Noto+Sans+SC:wght@400;700&display=swap\" rel=\"stylesheet\">\n</head>\n<body>\n    <div class=\"container\">\n        <header>\n            <h1 class=\"title\">Microsoft Hosts Picker 💊</h1>\n            <p class=\"description\" data-en=\"Optimize your Microsoft service connection speed\" data-zh=\"优化您的 Microsoft 服务连接速度\"></p>\n            <div class=\"language-switch\">\n                <button id=\"zh-btn\" class=\"active\">中文</button>\n                <button id=\"en-btn\">English</button>\n            </div>\n        </header>\n        <main>\n            <div class=\"features\">\n                <div class=\"feature\">\n                    <span class=\"emoji\">🚀</span>\n                    <h3 data-en=\"Fast Connection\" data-zh=\"快速连接\"></h3>\n                    <p data-en=\"Automatically select the fastest IP address\" data-zh=\"自动选择最快的 IP 地址\"></p>\n                </div>\n                <div class=\"feature\">\n                    <span class=\"emoji\">🛡️</span>\n                    <h3 data-en=\"Safe and Reliable\" data-zh=\"安全可靠\"></h3>\n                    <p data-en=\"Use official IP addresses to ensure security\" data-zh=\"使用官方 IP 地址，确保安全\"></p>\n                </div>\n                <div class=\"feature\">\n                    <span class=\"emoji\">⚙️</span>\n                    <h3 data-en=\"Easy to Use\" data-zh=\"易于使用\"></h3>\n                    <p data-en=\"Generate optimized hosts file with one click\" data-zh=\"一键生成优化后的 hosts 文件\"></p>\n                </div>\n            </div>\n            <div class=\"action-buttons\">\n                <a href=\"https://mshost.hee.ink/MicrosoftHostsPicker.zip\" class=\"cta-button download-button\" data-en=\"Download ZIP\" data-zh=\"下载 ZIP 文件\"></a>\n                <a href=\"https://github.com/ButaiKirin/MicrosoftHostsPicker\" class=\"cta-button github-button\" data-en=\"View on GitHub\" data-zh=\"在 GitHub 上查看\"></a>\n            </div>\n        </main>\n        <footer>\n            <p>\n                © <span id=\"copyright-years\"></span> ButaiKirin. Released under the <a href=\"https://github.com/ButaiKirin/MicrosoftHostsPicker/blob/main/LICENSE\" target=\"_blank\" rel=\"noopener noreferrer\">MIT License</a>.\n            </p>\n        </footer>\n    </div>\n    <script src=\"script.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "requirements.txt",
    "content": "ping3==4.0.4\n"
  },
  {
    "path": "script.js",
    "content": "document.addEventListener('DOMContentLoaded', () => {\n    const features = document.querySelectorAll('.feature');\n    const quickStart = document.querySelector('.quick-start');\n    \n    // 计算特性卡片动画的总持续时间\n    const lastFeatureDelay = 0.6; // 最后一个特性卡片的延迟\n    const featureAnimationDuration = 0.6; // 每个特性卡片的动画持续时间\n    const totalFeatureAnimationTime = lastFeatureDelay + featureAnimationDuration;\n\n\n    const zhBtn = document.getElementById('zh-btn');\n    const enBtn = document.getElementById('en-btn');\n\n    function setLanguage(lang) {\n        document.querySelectorAll('[data-en]').forEach(elem => {\n            elem.textContent = elem.getAttribute(`data-${lang}`);\n        });\n        \n        if (lang === 'en') {\n            zhBtn.classList.remove('active');\n            enBtn.classList.add('active');\n            document.documentElement.lang = 'en';\n        } else {\n            enBtn.classList.remove('active');\n            zhBtn.classList.add('active');\n            document.documentElement.lang = 'zh-CN';\n        }\n    }\n\n    zhBtn.addEventListener('click', () => setLanguage('zh'));\n    enBtn.addEventListener('click', () => setLanguage('en'));\n\n    // 自动检测浏览器语言\n    const userLang = navigator.language || navigator.userLanguage;\n    setLanguage(userLang.startsWith('zh') ? 'zh' : 'en');\n\n    // 设置版权年份\n    const copyrightYearsSpan = document.getElementById('copyright-years');\n    const startYear = 2021;\n    const currentYear = new Date().getFullYear();\n    copyrightYearsSpan.textContent = startYear === currentYear ? startYear : `${startYear}-${currentYear}`;\n\n    // 获取 GitHub star 数量\n    fetch('https://api.github.com/repos/ButaiKirin/MicrosoftHostsPicker')\n        .then(response => response.json())\n        .then(data => {\n            const starCount = document.getElementById('star-count');\n            starCount.textContent = data.stargazers_count;\n        })\n        .catch(error => console.error('Error fetching GitHub stats:', error));\n});\n"
  },
  {
    "path": "style.css",
    "content": ":root {\n    --bg-color: #F3F9FF;\n    --primary-color: #e87a90;\n    --secondary-color: #ffe8ea;\n    --text-color: #F596AA;\n    --accent-color: #e15e83;\n    --accent-color-rgb: 232, 48, 21;\n}\n\nbody {\n    font-family: 'Noto Sans SC', 'Noto Sans JP', sans-serif;\n    background-color: var(--bg-color);\n    color: var(--text-color);\n    margin: 0;\n    padding: 0;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    min-height: 100vh;\n}\n\n.container {\n    background-color: white;\n    border-radius: 24px;\n    padding: 2rem;\n    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\n    text-align: center;\n    max-width: 800px;\n    width: 90%;\n    transition: all 0.3s ease;\n}\n\n.container:hover {\n    transform: translateY(-5px);\n    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.15);\n}\n\n.title {\n    color: var(--primary-color);\n    font-size: 2.5rem;\n    margin-bottom: 0.5rem;\n    animation: fadeInDown 1s ease-out;\n}\n\n.description {\n    color: var(--text-color);\n    font-size: 1.2rem;\n    margin-bottom: 1rem;\n    animation: fadeInUp 1s ease-out 0.5s both;\n}\n\n.language-switch {\n    margin-bottom: 2rem;\n    animation: fadeInUp 0.6s ease-out 0.8s both;\n}\n\n.language-switch button {\n    background-color: transparent;\n    border: 1px solid var(--primary-color);\n    color: var(--primary-color);\n    padding: 0.5rem 1rem;\n    margin: 0 0.5rem;\n    border-radius: 20px;\n    cursor: pointer;\n    transition: all 0.3s ease;\n}\n\n.language-switch button.active {\n    background-color: var(--primary-color);\n    color: white;\n}\n\n.language-switch button:hover {\n    transform: translateY(-2px);\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.features {\n    display: flex;\n    justify-content: space-around;\n    margin-bottom: 2rem;\n}\n\n.feature {\n    flex: 1;\n    margin: 0 1rem;\n    padding: 1.5rem;\n    background-color: var(--secondary-color);\n    border-radius: 16px;\n    transition: all 0.3s ease;\n    animation: fadeInUp 0.6s ease-out backwards;\n    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);\n}\n\n.feature:hover {\n    transform: translateY(-5px);\n    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.25);\n}\n\n.emoji {\n    font-size: 3rem;\n    margin-bottom: 1rem;\n}\n\n.feature h3 {\n    color: var(--primary-color);\n    margin-bottom: 0.5rem;\n}\n\n.feature p {\n    color: var(--text-color);\n}\n\n.cta-button {\n    display: inline-block;\n    background-color: var(--accent-color);\n    color: white;\n    padding: 1rem 2rem;\n    border-radius: 30px;\n    text-decoration: none;\n    font-weight: bold;\n    font-size: 1.2rem;\n    transition: all 0.3s ease;\n    animation: \n        fadeInUp 0.6s ease-out 1s both,\n        pulse 2s infinite;\n    position: relative;\n    overflow: hidden;\n}\n\n.cta-button::before {\n    content: '';\n    position: absolute;\n    top: -50%;\n    left: -50%;\n    width: 200%;\n    height: 200%;\n    background: linear-gradient(\n        to right,\n        rgba(255, 255, 255, 0) 0%,\n        rgba(255, 255, 255, 0.3) 50%,\n        rgba(255, 255, 255, 0) 100%\n    );\n    transform: rotate(45deg);\n    animation: shimmer 3s infinite;\n}\n\n.cta-button:hover {\n    background-color: #C62700;\n    transform: translateY(-3px);\n    box-shadow: 0 6px 12px rgba(var(--accent-color-rgb), 0.3);\n}\n\n.cta-button:active {\n    transform: translateY(-1px);\n    box-shadow: 0 3px 6px rgba(var(--accent-color-rgb), 0.2);\n}\n\nfooter {\n    margin-top: 2rem;\n    font-size: 0.9rem;\n    color: var(--text-color);\n    text-align: center;\n}\n\nfooter a {\n    color: var(--primary-color);\n    text-decoration: none;\n}\n\nfooter a:hover {\n    text-decoration: underline;\n}\n\n@keyframes fadeInDown {\n    from {\n        opacity: 0;\n        transform: translateY(-20px);\n    }\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n\n@keyframes fadeInUp {\n    from {\n        opacity: 0;\n        transform: translateY(20px);\n    }\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n\n@keyframes fadeIn {\n    from { opacity: 0; }\n    to { opacity: 1; }\n}\n\n@keyframes pulse {\n    0% {\n        box-shadow: 0 0 0 0 rgba(var(--accent-color-rgb), 0.4);\n    }\n    70% {\n        box-shadow: 0 0 0 15px rgba(var(--accent-color-rgb), 0);\n    }\n    100% {\n        box-shadow: 0 0 0 0 rgba(var(--accent-color-rgb), 0);\n    }\n}\n\n@keyframes shimmer {\n    0% {\n        background-position: -100% 0;\n    }\n    100% {\n        background-position: 100% 0;\n    }\n}\n\n@media (max-width: 768px) {\n    .features {\n        flex-direction: column;\n    }\n    \n    .feature {\n        margin: 1rem 0;\n    }\n}\n\n\n.feature:nth-child(1) {\n    animation-delay: 0.2s;\n}\n\n.feature:nth-child(2) {\n    animation-delay: 0.4s;\n}\n\n.feature:nth-child(3) {\n    animation-delay: 0.6s;\n}\n\n.features {\n    margin-bottom: 3rem;\n}\n\n.quick-start {\n    margin-top: 3rem;\n}\n\n\n.steps ul, .usage-tips ul {\n    list-style-type: none;\n    padding-left: 0;\n    margin: 0;\n}\n\n.steps li, .usage-tips li {\n    margin-bottom: 1rem;\n}\n\n.github-stats {\n    display: flex;\n    justify-content: center;\n    margin: 1rem 0;\n    animation: fadeIn 1s ease-out;\n}\n\n.github-stars {\n    display: inline-flex;\n    align-items: center;\n    background-color: #f0f0f0;\n    color: #333;\n    padding: 0.5rem 1rem;\n    border-radius: 20px;\n    text-decoration: none;\n    font-size: 0.9rem;\n    transition: all 0.3s ease;\n    box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n}\n\n.github-stars:hover {\n    background-color: #e0e0e0;\n    transform: translateY(-2px);\n    box-shadow: 0 4px 8px rgba(0,0,0,0.15);\n}\n\n.github-stars svg {\n    margin-right: 0.5rem;\n    fill: #f1e05a;\n}\n\n.action-buttons {\n    display: flex;\n    justify-content: center;\n    gap: 1rem;\n    margin-top: 2rem;\n}\n\n.cta-button {\n    display: inline-block;\n    padding: 0.8rem 1.5rem;\n    border-radius: 30px;\n    text-decoration: none;\n    font-weight: bold;\n    font-size: 1rem;\n    transition: all 0.3s ease;\n    text-align: center;\n}\n\n.download-button {\n    background-color: var(--accent-color);\n    color: white;\n}\n\n.download-button:hover {\n    background-color: #C62700;\n    transform: translateY(-3px);\n    box-shadow: 0 4px 8px rgba(232, 48, 21, 0.3);\n}\n\n.github-button {\n    background-color: #f0f0f0;\n    color: #333;\n}\n\n.github-button:hover {\n    background-color: #e0e0e0;\n    transform: translateY(-3px);\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n}\n\n@keyframes fadeInUp {\n    from {\n        opacity: 0;\n        transform: translateY(20px);\n    }\n    to {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n\n.action-buttons {\n    animation: fadeInUp 0.6s ease-out 1s both;\n}\n"
  }
]