javascript implementation
This commit is contained in:
parent
1853215191
commit
d90f87efe3
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;
|
Loading…
Reference in New Issue
Block a user