import requests from requests.adapters import HTTPAdapter, Retry from datetime import datetime, timedelta from rich.table import Table from rich.console import Console console = Console() table = Table(title="VSCode Extensions") def get_vscode_extensions( id, max_page=10000, page_size=100, include_versions=True, include_files=True, include_category_and_tags=True, include_shared_accounts=True, include_version_properties=True, exclude_non_validated=False, include_installation_targets=True, include_asset_uri=True, include_statistics=True, include_latest_version_only=False, unpublished=False, include_name_conflict_info=True, api_version="7.2-preview.1", session=None, ): if not session: session = requests.session() headers = {"Accept": f"application/json; charset=utf-8; api-version={api_version}"} flags = 0 if include_versions: flags |= 0x1 if include_files: flags |= 0x2 if include_category_and_tags: flags |= 0x4 if include_shared_accounts: flags |= 0x8 if include_shared_accounts: flags |= 0x8 if include_version_properties: flags |= 0x10 if exclude_non_validated: flags |= 0x20 if include_installation_targets: flags |= 0x40 if include_asset_uri: flags |= 0x80 if include_statistics: flags |= 0x100 if include_latest_version_only: flags |= 0x200 if unpublished: flags |= 0x1000 if include_name_conflict_info: flags |= 0x8000 for page in range(1, max_page + 1): body = { "filters": [ { "criteria": [{"filterType": 7, "value": id}], "pageNumber": page, "pageSize": page_size, "sortBy": 0, "sortOrder": 0, } ], "assetTypes": [], "flags": flags, } r = session.post( "https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery", json=body, headers=headers, ) r.raise_for_status() response = r.json() extensions = response["results"][0]["extensions"] for extension in extensions: yield extension if len(extensions) != page_size: break def main(): retry_strategy = Retry( total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504], allowed_methods=["HEAD", "GET", "OPTIONS"], ) adapter = HTTPAdapter(max_retries=retry_strategy) session = requests.Session() session.mount("https://", adapter) session.mount("http://", adapter) details = [] categories = {} used = set() table.add_column("Name", style="cyan", no_wrap=True) table.add_column("Version") table.add_column("Last Update") table.add_column("Install Count", justify="right") table.add_column("Description") for id in open("vscode-extensions.txt").readlines(): for extension in get_vscode_extensions(id.strip(), session=session): extension_name = extension["extensionName"] extension_description = extension.get("shortDescription", "") extensions_versions = extension["versions"] extension_last_update = extension["lastUpdated"] last_update_dt = datetime.strptime( extension_last_update, "%Y-%m-%dT%H:%M:%S.%fZ" ) last_update = last_update_dt.strftime("%Y-%m-%d") extension_categories = extension["categories"] extensions_statistics = dict( { (item["statisticName"], item["value"]) for item in extension["statistics"] } ) extension_version_info = extensions_versions.pop(0) extension_version = extension_version_info["version"] table.add_row( extension_name, extension_version, last_update, str(round(extensions_statistics.get("install", 0))), extension_description, ) info = f"{id.strip():50} {last_update:10} {str(round(extensions_statistics.get("install", 0))):>12} {extension_description}" for cat in extension_categories: if info in used: continue used.add(cat) categories.setdefault(cat, []).append(info) details.append(info) break console.print(table) with open("vscode-extensions-with-desc.txt", "w") as f: f.write("\n".join(details)) with open("vscode-extensions-categories.txt", "w") as f: for cat, extensions in sorted(categories.items()): f.write(f"{cat}\n") f.write("\n".join(extensions)) f.write("\n\n---\n\n") if __name__ == "__main__": main()