javascript implementation
This commit is contained in:
		
							
								
								
									
										36
									
								
								playerLookup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								playerLookup.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     <title>Chess.com PGN Downloader</title> | ||||||
|  |     <style> | ||||||
|  |         body { | ||||||
|  |             font-family: Arial, sans-serif; | ||||||
|  |             text-align: center; | ||||||
|  |             margin: 50px; | ||||||
|  |         } | ||||||
|  |         #usernameInput { | ||||||
|  |             padding: 8px; | ||||||
|  |             font-size: 16px; | ||||||
|  |         } | ||||||
|  |         #downloadButton { | ||||||
|  |             padding: 10px; | ||||||
|  |             font-size: 18px; | ||||||
|  |             cursor: pointer; | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |     <h1>Chess.com PGN Downloader</h1> | ||||||
|  |      | ||||||
|  |     <label for="usernameInput">Enter Chess.com Username:</label> | ||||||
|  |     <input type="text" id="usernameInput" placeholder="Enter username"> | ||||||
|  |  | ||||||
|  |     <br><br> | ||||||
|  |  | ||||||
|  |     <button id="downloadButton" onclick="downloadPGN()">Download PGN</button> | ||||||
|  |  | ||||||
|  |     <script type="module" src="./player_games.js"></script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										91
									
								
								player_games.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								player_games.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | // mainScript.js | ||||||
|  |  | ||||||
|  | import userAgents from './userAgents.js'; | ||||||
|  |  | ||||||
|  | // Declare the script variable | ||||||
|  | // | ||||||
|  | let script; | ||||||
|  |  | ||||||
|  | window.downloadPGN = function() { | ||||||
|  |     const username = document.getElementById('usernameInput').value; | ||||||
|  |  | ||||||
|  |     if (!username) { | ||||||
|  |         alert('Please enter a username.'); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Create a callback function to handle the JSONP response for archives | ||||||
|  |     const archivesCallback = 'handleArchivesResponse'; | ||||||
|  |     window[archivesCallback] = function(data) { | ||||||
|  |         document.head.removeChild(script); // Remove the script element after execution | ||||||
|  |         threddGames(data); // Pass the list of archive URLs to the threaded function | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Fetch player archives using JSONP | ||||||
|  |     playerArchives(username, archivesCallback); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | function getRandomUserAgent() { | ||||||
|  |     return userAgents[Math.floor(Math.random() * userAgents.length)]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function playerArchives(username, callback) { | ||||||
|  |     // Replace 'YOUR_API_KEY' with your Chess.com API key | ||||||
|  |     const url = `https://api.chess.com/pub/player/${username}/games/archives`; | ||||||
|  |     const response = await fetch(url); | ||||||
|  |     const data = await response.json(); | ||||||
|  |     window[callback](data.archives); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function playerMonthly(url, callback) { | ||||||
|  |     const user_agent = getRandomUserAgent(); | ||||||
|  |     const headers = { | ||||||
|  |         'User-Agent': user_agent, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const response = await fetch(url + '/pgn', { headers }); | ||||||
|  |     const games = await response.text(); | ||||||
|  |     window[callback](games); // Execute the callback function with the PGN data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function threddGames(archiveURLs) { | ||||||
|  |     const gamesList = []; | ||||||
|  |  | ||||||
|  |     // Using Promise.all to wait for all threads to complete | ||||||
|  |     await Promise.all(archiveURLs.map(async (url) => { | ||||||
|  |         return new Promise(async (resolve) => { | ||||||
|  |             const monthlyGamesCallback = 'handleMonthlyGamesResponse'; | ||||||
|  |             window[monthlyGamesCallback] = function(data) { | ||||||
|  |                 handleDownload(data, gamesList, resolve); | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             // Fetch monthly games using JSONP | ||||||
|  |             await playerMonthly(url, monthlyGamesCallback); | ||||||
|  |         }); | ||||||
|  |     })); | ||||||
|  |  | ||||||
|  |     // Combine and save the games to a file | ||||||
|  |     const pgnDb = gamesList.join('\n\n'); | ||||||
|  |     const username = document.getElementById('usernameInput').value; | ||||||
|  |     createDownloadLink(pgnDb, `${username}.pgn`); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function handleDownload(data, gamesList, resolve) { | ||||||
|  |     gamesList.push(data); | ||||||
|  |     resolve(); // Resolve the promise to indicate completion of this thread | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function createDownloadLink(data, filename) { | ||||||
|  |     const blob = new Blob([data], { type: 'application/octet-stream' }); | ||||||
|  |     const url = URL.createObjectURL(blob); | ||||||
|  |  | ||||||
|  |     const a = document.createElement('a'); | ||||||
|  |     a.href = url; | ||||||
|  |     a.download = filename; | ||||||
|  |  | ||||||
|  |     document.body.appendChild(a); | ||||||
|  |     a.click(); | ||||||
|  |  | ||||||
|  |     document.body.removeChild(a); | ||||||
|  |     URL.revokeObjectURL(url); | ||||||
|  | } | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| import user_agents |  | ||||||
| import random |  | ||||||
| import requests |  | ||||||
| import re |  | ||||||
| import os |  | ||||||
| import json |  | ||||||
| import concurrent.futures |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def playerArchives(username): |  | ||||||
|     # Create archive list. This is a list of pages containing lists of games used for futher downloading |  | ||||||
|  |  | ||||||
|     user_agent = random.choice(user_agents.user_agents) # load up random user agent from list |  | ||||||
|     headers = { |  | ||||||
|             'User-Agent':user_agent |  | ||||||
|             } |  | ||||||
|     url = f"https://api.chess.com/pub/player/{username}/games/archives" |  | ||||||
|     archive = requests.get(url, headers=headers).json()['archives'] |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         cwd = os.getcwd() |  | ||||||
|         path = os.path.join(cwd, 'archives') |  | ||||||
|         os.makedirs(path) |  | ||||||
|     except OSError: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     file_name = os.path.join(path, username+'_archive.txt') |  | ||||||
|     with open(file_name, 'w') as f: |  | ||||||
|         json.dump(archive, f) |  | ||||||
|  |  | ||||||
|     return archive |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def playerMonthly(url=None): |  | ||||||
|  |  | ||||||
|     user_agent = random.choice(user_agents.user_agents) # load up random user agent from list |  | ||||||
|     headers = { |  | ||||||
|             'User-Agent':user_agent |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|     if url: |  | ||||||
|         url=url+'/pgn' # connect to multi-game pgn download endpoint by appending a "pgn" to the url provided by url in archive list |  | ||||||
|     else: |  | ||||||
|         username=input("username: ") |  | ||||||
|         YYYY=input("year in YYYY: ") |  | ||||||
|         MM=input("month in MM: ")  |  | ||||||
|         url = f"https://api.chess.com/pub/player/{username}/games/{YYYY}/{MM}/pgn" |  | ||||||
|  |  | ||||||
|     # get and save games list in .pgn format |  | ||||||
|     games = requests.get(url, headers=headers).content.decode("utf-8") |  | ||||||
|  |  | ||||||
|     return games |  | ||||||
|  |  | ||||||
| # Multithreaded games download |  | ||||||
| def threddGames(username=None, archive=None): |  | ||||||
|  |  | ||||||
|     if archive: |  | ||||||
|         with open(archive) as f: |  | ||||||
|             archive = json.load(f) |  | ||||||
|     else: |  | ||||||
|         archive = playerArchives(username) |  | ||||||
|  |  | ||||||
|     # async download games |  | ||||||
|     games_list = [] |  | ||||||
|     with concurrent.futures.ThreadPoolExecutor() as executor: |  | ||||||
|         for future in executor.map(playerMonthly, archive): |  | ||||||
|             games_list.extend(future) |  | ||||||
|     pgn_db = "\n\n".join(games_list) |  | ||||||
|     with open(username+'.pgn', 'w') as f: |  | ||||||
|         f.write(pgn_db) |  | ||||||
|  |  | ||||||
|     return pgn_db |  | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								test.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								test.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     <title>File Download App</title> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  |     <button id="downloadButton">Download File</button> | ||||||
|  |  | ||||||
|  |     <script> | ||||||
|  |         // Function to trigger the download | ||||||
|  |         function downloadFile() { | ||||||
|  |             // Create a Blob containing the file data | ||||||
|  |             var fileData = "Hello, this is the content of the file!"; // this will end up being the concatenated .pgn results returned by the async function | ||||||
|  |             var blob = new Blob([fileData], { type: "text/plain" }); | ||||||
|  |  | ||||||
|  |             // Create an anchor element and set its attributes | ||||||
|  |             var a = document.createElement("a"); | ||||||
|  |             a.href = window.URL.createObjectURL(blob); | ||||||
|  |             a.download = "example.txt"; | ||||||
|  |  | ||||||
|  |             // Append the anchor element to the body | ||||||
|  |             document.body.appendChild(a); | ||||||
|  |  | ||||||
|  |             // Programmatically click the anchor to trigger the download | ||||||
|  |             a.click(); | ||||||
|  |  | ||||||
|  |             // Remove the anchor from the body | ||||||
|  |             document.body.removeChild(a); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Attach the downloadFile function to the button click event | ||||||
|  |         document.getElementById("downloadButton").addEventListener("click", downloadFile); | ||||||
|  |     </script> | ||||||
|  |  | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @@ -1,8 +1,14 @@ | |||||||
| user_agents = [ | 
 | ||||||
|  | // userAgents.js
 | ||||||
|  | 
 | ||||||
|  | const userAgents = [ | ||||||
|     "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", |     "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", | ||||||
|     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", |     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", | ||||||
|     "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", |     "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", | ||||||
|     "Mozilla/5.0 (Windows NT 6.1; rv:109.0) Gecko/20100101 Firefox/113.0", |     "Mozilla/5.0 (Windows NT 6.1; rv:109.0) Gecko/20100101 Firefox/113.0", | ||||||
|     "Mozilla/5.0 (Android 12; Mobile; rv:109.0) Gecko/113.0 Firefox/113.0", |     "Mozilla/5.0 (Android 12; Mobile; rv:109.0) Gecko/113.0 Firefox/113.0", | ||||||
|     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/113.0", |     "mozilla/5.0 (macintosh; intel mac os x 10.15; rv:109.0) gecko/20100101 firefox/113.0", | ||||||
| ] |   // Add more user agents as needed
 | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | export default userAgents; | ||||||
		Reference in New Issue
	
	Block a user