From 96f2b1f0bfdc42e81a873b7adeb5b28f79669c33 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Thu, 27 Aug 2020 15:56:19 +0200 Subject: [PATCH 01/15] Refactor variable and function names --- server/html/index.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/server/html/index.php b/server/html/index.php index d7a9df4..070cc71 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -6,7 +6,7 @@ // Returns the best time of the specified user along with the rank that this time // results in compared to the times by other users. - function get_best_time_by_user($bestTimes, $user) { + function getBestTimeByUser($bestTimes, $user) { $rank = 1; for ($i = 0; $i < count($bestTimes); $i++) { $bestTime = $bestTimes[$i]; @@ -21,17 +21,17 @@ function get_best_time_by_user($bestTimes, $user) { return null; } - - function table_for_track_set($track_set, $selectedUser) { - if ($track_set == "Training") + + function tableForTrackSet($trackSet, $selectedUser) { + if ($trackSet == "Training") $count = 25; - else if ($track_set == "Summer 2020") { + else if ($trackSet == "Summer 2020") { $count = 25; } else { throw Exception("Unknown track set"); } - - echo "

".htmlspecialchars($track_set)." - Records

"; + + echo "

".htmlspecialchars($trackSet)." - Records

"; ?> @@ -55,7 +55,7 @@ function table_for_track_set($track_set, $selectedUser) { for ($i = 1; $i <= 25; $i++) { - $track = sprintf("$track_set - %02d", $i); + $track = sprintf("$trackSet - %02d", $i); // Determine best time for track. $st = $pdo->prepare("SELECT user, best FROM records WHERE track = :track ORDER BY best ASC"); @@ -78,7 +78,7 @@ function table_for_track_set($track_set, $selectedUser) { ".($bestTimeByUser[0] / 1000.0)."s\n"; echo " \n"; @@ -101,7 +101,7 @@ function table_for_track_set($track_set, $selectedUser) { ?>
".sprintf("%.3f", $bestTimeByUser[0] / 1000.0 - $bestTime / 1000.0)."s
-".htmlspecialchars($track_set)." - Total time per user"; ?> +".htmlspecialchars($trackSet)." - Total time per user"; ?> @@ -114,7 +114,7 @@ function table_for_track_set($track_set, $selectedUser) { $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count = 25 ORDER BY count DESC, total_time ASC"); - $st->bindValue('track_set', addcslashes("$track_set", "?%")."%", PDO::PARAM_STR); + $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); $st->execute(); while ($row = $st->fetch()) { //print_r($row); @@ -154,8 +154,8 @@ function table_for_track_set($track_set, $selectedUser) {

Trackmania Records

- - + +

Upload instructions

From ff44521724c4c2609735e66d7a26246b4bee3364 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Thu, 27 Aug 2020 16:05:28 +0200 Subject: [PATCH 02/15] Fix total time per user for users that have not driven all tracks --- server/html/index.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/html/index.php b/server/html/index.php index 070cc71..81a2dfc 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -125,8 +125,10 @@ function tableForTrackSet($trackSet, $selectedUser) { query("SELECT user, COUNT(track) AS count FROM records GROUP BY user HAVING count < 25 ORDER BY LOWER(user)"); - while ($row = $results->fetch()) { + $st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count < 25 ORDER BY count DESC, total_time ASC"); + $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); + $st->execute(); + while ($row = $st->fetch()) { //print_r($row); ?>
From 09d11e4d9bf907322a329f27c5f9fe618dfd20f1 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Thu, 27 Aug 2020 20:22:17 +0200 Subject: [PATCH 03/15] Add background color to track groups (5 tracks each) --- server/html/index.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/server/html/index.php b/server/html/index.php index 81a2dfc..ee0d59c 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -32,7 +32,7 @@ function tableForTrackSet($trackSet, $selectedUser) { } echo "

".htmlspecialchars($trackSet)." - Records

"; - ?> +?>
@@ -72,7 +72,23 @@ function tableForTrackSet($trackSet, $selectedUser) { $st->execute(); $users = $st->fetchAll(PDO::FETCH_COLUMN, 0); //print_r($users); -?> + + if ($trackSet == "Summer 2020") { + if ($i <= 5) { + $tableColorClass = " class='table-light'"; + } else if ($i <= 10) { + $tableColorClass = " class='table-success'"; + } else if ($i <= 15) { + $tableColorClass = " class='table-primary'"; + } else if ($i <= 20) { + $tableColorClass = " class='table-danger'"; + } else if ($i <= 25) { + $tableColorClass = " class='table-secondary'"; + } + } else { + $tableColorClass = ""; + } +?> > @@ -91,14 +107,14 @@ function tableForTrackSet($trackSet, $selectedUser) { echo " \n"; } } - ?> +?> getMessage()); } - ?> +?>
s -
".htmlspecialchars($trackSet)." - Total time per user"; ?> From a983e3cec087ada841ecd36648a3ef409de422bb Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 15:07:19 +0200 Subject: [PATCH 04/15] Improve error handling --- server/html/upload.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/html/upload.php b/server/html/upload.php index e9aae6d..d5c623b 100644 --- a/server/html/upload.php +++ b/server/html/upload.php @@ -64,5 +64,6 @@ echo "Success!"; } catch (PDOException $e) { - echo 'Database error: '.$e->getMessage(); + http_response_code(500); + die('Database error: '.$e->getMessage()); } From 8f1daf0dc842b8bcbfb2b6e0ef541b4d44c00d79 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:20:32 +0200 Subject: [PATCH 05/15] Check for database.db existence --- server/html/index.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/html/index.php b/server/html/index.php index ee0d59c..3fe5231 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -172,8 +172,14 @@ function tableForTrackSet($trackSet, $selectedUser) {

Trackmania Records

- - +No records have been uploaded yet...

"; + } +?>

Upload instructions

From c263887d1f8c5f5199d263fc0188f1daddbc7f7c Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:21:15 +0200 Subject: [PATCH 06/15] Add README.md --- README.md | 26 ++++++++++++++++++++++++++ client/README.md | 11 ++++++----- screenshot1.png | Bin 0 -> 52890 bytes screenshot2.png | Bin 0 -> 22187 bytes server/README.md | 24 ++++++++++++++++++++++++ server/html/index.php | 8 +++++--- 6 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 README.md create mode 100644 screenshot1.png create mode 100644 screenshot2.png create mode 100644 server/README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..2236151 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# trackmania-records + +This project allows you to compare your Trackmania 2020 records with your friends. + +In the browser, it looks like this: + +![Screenshot 1](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot1.png "Screenshot 1") + +It also features a total time comparison: + +![Screenshot 2](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot2.png "Screenshot 2") + +## Setup + +### 1. Install web application + +Please refer to: https://github.com/rsnitsch/trackmania-records/tree/develop/client + +### 2. Install uploader + +The uploader is what extracts your trackmania records from the autosaved replay files on +your computer and sends them to the web application. + +The installation and usage instructions for the upload tool can be found at the bottom of +the web application index page. Alternatively, you can look them up here: +https://github.com/rsnitsch/trackmania-records/tree/develop/client diff --git a/client/README.md b/client/README.md index 085b339..e43921d 100644 --- a/client/README.md +++ b/client/README.md @@ -1,9 +1,10 @@ -Trackmania records uploader -=========================== +trackmania-records - Uploader +============================= -This tool extracts your records for the training maps of the latest -Trackmania version (from 2020) and uploads them to a server so you can -easily share your records with friends. +This is the uploader for trackmania-records, a Trackmania 2020 records sharing/comparison tool. + +The uploader extracts your records for the training maps of the latest Trackmania version (from 2020) +and uploads them to the web application server so you can easily share your records with friends. Install (requires Python 3 on your system): diff --git a/screenshot1.png b/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..60ca4126388668ced19fbf3fbc245de54fb74a10 GIT binary patch literal 52890 zcmd43bx>T}y0?pjKnNBH-na(00F65Yg1c*QZQLPvfX3ZIaCdh}a0u?+xVyvcthM&t zXPF&^^EP1$a+0XX1jsNjFsPrT#FSuQ;IN=iRwOv+ zh+AHn9Q4NIyj;B+I(_i9hbFpTLvbXE{jkhL_357b>( z)Ss<2`JCmI!ZbMzokA!;3@n?CT2@w^1Tg1C&qTxE3kBqkh=Nna+z(Zptb82E`(~US zW#UBJ!~67CT4aLy+V$tch@j^f1D%I$d2kxN+4KFm9zJo4&tn$5(+u?N$Pr@#mUI}o zxE$B#i0^pX?-9iR{et{7df&T!Z|x^F%D)beHo@=gI35>;1%w{>NEAGnb*XfC$U7!* zza}@6a;`0CHzO!88oVg*comi9yRnGQ`N5m1<0`{Uuef8;$DL{Jd7N3_XM54N=jN-+ zOF)#s{bL#pbCB845V_>u~Zv+x4Fhi6yf<}BAM3!c-% zF+t~uT{`(hqa-;JkNt5wep25$cxGZ=XJEa?0dLu1tqL(^dU{QV&t6do$s84+GlZXF zOBJ~F^XpZI+|z@MJpaAHByrQgdKcon`rFaO+0_x}_GuMF;9845kN4pnO?<%8{3S~Z z{YLl|5!yqloq(rMlh>iuOe=DDkiR@##WL1dyTg44L(or;_I9tkK?;5nfP3(Xx7lPk z2~{Ne`KEr`kEM`vD%&yU8Bb}=HKRpSr*Hr`{yaLw_1F!;iD8Po4b1-w)azn!P^J+=iVZMU20@W{)~71-WhD zYtVqi79t&9{9T!%RN88AHqCsLuITWH4c&7O;`48k#>-cE%v|=I zlbGG^-^eN=%1d0fv^+Xq1S~yFkgRhS`A83?II4C~2W{ti%7YEorY3nyP;P%at*l;j zuJR#A0sCsR;oSy$aEF(ocXzi~f1UE(cC6pYc;l3(0luu8-|#(7&cxnT+^0XrnT}Of zm}h<(cNXv_@LA6b54oY!KMFHL?@=robFxlfewYC{-&8$Lk~b4y!OX#*3^5B73nYTZ z&TFpEs|Vf*I4b~RZpu!CtX)+eydurkOe$M#A+!xIDn0;<`v%jTr+6lS)kJ2`NylSF zD$<({fpqdXqR{0A2xe|YQF_lH#Vh$2r?|7a$&5Q)`7C?pY45ww{f4!?+)}rx`*nUN zx1SP}37!HJ;C|sF>OGzrHp&yL+H#U3?q$Yp;?n57mb~kXtH`>NWvWI_{`}ziGG6+S zvE;i}7ngL4Y;^0j$GBxU??zd(yL$#aHZC~E$8<4!x}}kCbI&6N#ZUU)RUKMgA9_C- z6)jZUw>%IV%Fp2TriSFr(MZ2(acw^z?+dv;mwbpamPw_VpY13BT%!vNr!_@kXX0Fu zW_fQn@mrT(0jo?)`3`Q^5I!Pv@c4Q3SDBr#pLkghSRUjJ)?7zrE|#SG*RUUmpp7Kl zuj`{QsmxzL3v4O1J2lHV>KjBC6GI$*NAV3L?dMyF@A@{eRl~#MGG%C<_k5o_7AP2= zcIaihF>bzj$dq<_Y#MHj8_v>aB^1YOwr#F%^{vLH&|hTufX?G`9qRUbDzYZkFcZy0 zcl6B8jz@Jphvh7e<(UuTdwOR_)uz_Eh!+KUPRQ*(H8()!CTkmh)$AnbKVQ≠ie{ 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 Ks1!5&^1lGp1@f%` literal 0 HcmV?d00001 diff --git a/screenshot2.png b/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..20e7cf2673b4169b02f124a675a0903713ad82c4 GIT binary patch literal 22187 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 !JjtK}f+$bXdvWqveScG&LEImJ+ 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 - Trackmania Records + trackmania-records
-

Trackmania Records

+

trackmania-records

Upload instructions +

To upload your Trackmania 2020 records to this page, follow these instructions:

+
  • Download Python 3 from python.org and install it: https://www.python.org/downloads/
  • Open a shell/terminal window (cmd.exe or PowerShell)
  • -
  • Install the upload script by executing this command:
    +
  • Install the upload tool by executing this command:
    pip3 install --upgrade upload-tm-records
  • Now you can always run the following command to upload your latest records to this server:
    upload-tm-records.exe
  • From a5d9e49266ed6b0673e9f9a824a0e3d55d399b98 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:22:30 +0200 Subject: [PATCH 07/15] Fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2236151..8989659 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ It also features a total time comparison: ### 1. Install web application -Please refer to: https://github.com/rsnitsch/trackmania-records/tree/develop/client +Please refer to: https://github.com/rsnitsch/trackmania-records/tree/develop/server ### 2. Install uploader From 9ee825f63fead7f9e55a532def0439d60b168c53 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:23:24 +0200 Subject: [PATCH 08/15] Remove screenshots from web app README --- server/README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server/README.md b/server/README.md index 1ea1aa1..846d6ac 100644 --- a/server/README.md +++ b/server/README.md @@ -4,14 +4,6 @@ This is the web application part of trackmania-records, a Trackmania 2020 records sharing tool. The web application is where all your records (and the records of your friends) will be stored, displayed and compared to each other. -In the browser, it looks like this: - -![Screenshot 1](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot1.png "Screenshot 1") - -It also features a total time comparison: - -![Screenshot 2](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot2.png "Screenshot 2") - ## Requirements - PHP with PDO/SQLite support From 3624b9e5ec2914082bb1c501bb4905671ad60de7 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:24:54 +0200 Subject: [PATCH 09/15] Add LICENSE.txt --- LICENSE.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..9aa03b3 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . From f19b3be43d96cc450cf46ea7233b41c9b8986901 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:34:55 +0200 Subject: [PATCH 10/15] Add footer with link to Github project page --- server/html/index.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/html/index.php b/server/html/index.php index a511638..92b6767 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -193,6 +193,10 @@ function tableForTrackSet($trackSet, $selectedUser) {
  • Now you can always run the following command to upload your latest records to this server:
    upload-tm-records.exe
+ +
+ +

trackmania-records is opensource: github.com/rsnitsch/trackmania-records

\ No newline at end of file From 0fa5f8b2237d090815228f3e95c4343bf736b610 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Fri, 28 Aug 2020 16:47:33 +0200 Subject: [PATCH 11/15] Improve style for background color of track groups --- server/html/index.php | 11 ++++++----- server/html/style.css | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 server/html/style.css diff --git a/server/html/index.php b/server/html/index.php index 92b6767..59efaf9 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -75,15 +75,15 @@ function tableForTrackSet($trackSet, $selectedUser) { if ($trackSet == "Summer 2020") { if ($i <= 5) { - $tableColorClass = " class='table-light'"; + $tableColorClass = " class='whiteTracks'"; } else if ($i <= 10) { - $tableColorClass = " class='table-success'"; + $tableColorClass = " class='greenTracks'"; } else if ($i <= 15) { - $tableColorClass = " class='table-primary'"; + $tableColorClass = " class='blueTracks'"; } else if ($i <= 20) { - $tableColorClass = " class='table-danger'"; + $tableColorClass = " class='redTracks'"; } else if ($i <= 25) { - $tableColorClass = " class='table-secondary'"; + $tableColorClass = " class='blackTracks'"; } } else { $tableColorClass = ""; @@ -166,6 +166,7 @@ function tableForTrackSet($trackSet, $selectedUser) { trackmania-records + diff --git a/server/html/style.css b/server/html/style.css new file mode 100644 index 0000000..26a177a --- /dev/null +++ b/server/html/style.css @@ -0,0 +1,39 @@ +tr.whiteTracks td:first-child { + background: linear-gradient(90deg, white 3px, transparent 3px); +} + +tr.whiteTracks td:last-child { + background: linear-gradient(270deg, white 3px, transparent 3px); +} + +tr.greenTracks td:first-child { + background: linear-gradient(90deg, green 3px, transparent 3px); +} + +tr.greenTracks td:last-child { + background: linear-gradient(270deg, green 3px, transparent 3px); +} + +tr.blueTracks td:first-child { + background: linear-gradient(90deg, blue 3px, transparent 3px); +} + +tr.blueTracks td:last-child { + background: linear-gradient(270deg, blue 3px, transparent 3px); +} + +tr.redTracks td:first-child { + background: linear-gradient(90deg, red 3px, transparent 3px); +} + +tr.redTracks td:last-child { + background: linear-gradient(270deg, red 3px, transparent 3px); +} + +tr.blackTracks td:first-child { + background: linear-gradient(90deg, black 3px, transparent 3px); +} + +tr.blackTracks td:last-child { + background: linear-gradient(270deg, black 3px, transparent 3px); +} \ No newline at end of file From b4b5a2ccf8c0de7864eb60725f2ef6035e5dbde2 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Tue, 1 Sep 2020 16:29:26 +0200 Subject: [PATCH 12/15] Escape backslashes in docstring --- client/src/upload_tm_records.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/upload_tm_records.py b/client/src/upload_tm_records.py index 377fc2f..93c84de 100644 --- a/client/src/upload_tm_records.py +++ b/client/src/upload_tm_records.py @@ -18,8 +18,8 @@ def get_replay_directory(): Return the Trackmania 2020 Autosaves replay directory. Note: - In some cases, Trackmania 2020 uses the Documents\Trackmania2020 subfolder. Sometimes, - it uses the Documents\Trackmania subfolder (without any 2020 indication). + In some cases, Trackmania 2020 uses the Documents\\Trackmania2020 subfolder. Sometimes, + it uses the Documents\\Trackmania subfolder (without any 2020 indication). I assume that it uses Trackmania2020 if another (older) Trackmania version is installed on the system. Therefore, it seems prudent to try the Trackmania2020 subfolder From 529315a5c060cbfb3b8b5a61341239b8b779ffd0 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Sun, 4 Oct 2020 17:36:54 +0200 Subject: [PATCH 13/15] Add support for Fall, Winter and Spring seasons 2020+ --- client/src/upload_tm_records.py | 277 ++++++++++++++++---------------- 1 file changed, 139 insertions(+), 138 deletions(-) diff --git a/client/src/upload_tm_records.py b/client/src/upload_tm_records.py index 93c84de..ffa7227 100644 --- a/client/src/upload_tm_records.py +++ b/client/src/upload_tm_records.py @@ -1,138 +1,139 @@ -import argparse -import json -import logging -import os -import platform -import re -import sys - -import requests - -__version__ = '1.0.0b1' - -logger = logging.getLogger(__name__) - - -def get_replay_directory(): - """ - Return the Trackmania 2020 Autosaves replay directory. - - Note: - In some cases, Trackmania 2020 uses the Documents\\Trackmania2020 subfolder. Sometimes, - it uses the Documents\\Trackmania subfolder (without any 2020 indication). - - I assume that it uses Trackmania2020 if another (older) Trackmania version is - installed on the system. Therefore, it seems prudent to try the Trackmania2020 subfolder - first and use the Trackmania subfolder as a fallback. - """ - replay_directory = os.path.expanduser(r'~\Documents\Trackmania2020\Replays\Autosaves') - if os.path.isdir(replay_directory): - return replay_directory - else: - logging.warning("Replay directory was not found at expected location: %s.", replay_directory) - - replay_directory = os.path.expanduser(r'~\Documents\Trackmania\Replays\Autosaves') - if os.path.isdir(replay_directory): - return replay_directory - else: - logging.warning("Replay directory was not found at expected location: %s.", replay_directory) - logging.warning("Will now try to use the Windows API workaround for finding the directory...") - - # Windows allows to change the location of the Documents folder, e.g. to move - # it to a separate harddrive or a network drive. In this case, the above code must fail. Instead, - # we have to ask the Windows API for the location of the Documents folder. - import ctypes.wintypes - CSIDL_PERSONAL = 5 # My Documents - SHGFP_TYPE_CURRENT = 0 # Get current value (instead of default value) - - buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH) - ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PERSONAL, None, SHGFP_TYPE_CURRENT, buf) - - replay_directory = buf.value + r"\Trackmania2020\Replays\Autosaves" - if os.path.isdir(replay_directory): - return replay_directory - - replay_directory = buf.value + r"\Trackmania\Replays\Autosaves" - if os.path.isdir(replay_directory): - return replay_directory - - return None - - -def extract_record_from_gbx_file(path): - best_regexp = re.compile(b' Date: Sun, 4 Oct 2020 17:38:04 +0200 Subject: [PATCH 14/15] Add Fall 2020 season --- server/html/index.php | 405 +++++++++++++++++++++--------------------- 1 file changed, 203 insertions(+), 202 deletions(-) diff --git a/server/html/index.php b/server/html/index.php index 59efaf9..ec701a0 100644 --- a/server/html/index.php +++ b/server/html/index.php @@ -1,203 +1,204 @@ - $bestTime['best']) { - $rank++; - } - } - - return null; - } - - function tableForTrackSet($trackSet, $selectedUser) { - if ($trackSet == "Training") - $count = 25; - else if ($trackSet == "Summer 2020") { - $count = 25; - } else { - throw Exception("Unknown track set"); - } - - echo "

".htmlspecialchars($trackSet)." - Records

"; -?> - - - - - - -".htmlspecialchars($selectedUser)."'s time\n"; - echo " \n"; - echo " \n"; - echo " \n"; - } -?> - -setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - - for ($i = 1; $i <= 25; $i++) { - $track = sprintf("$trackSet - %02d", $i); - - // Determine best time for track. - $st = $pdo->prepare("SELECT user, best FROM records WHERE track = :track ORDER BY best ASC"); - $st->bindParam(':track', $track, PDO::PARAM_STR); - $st->execute(); - $bestTimes = $st->fetchAll(); - //print_r($bestTimes); - $bestTime = $bestTimes[0]['best']; - - // Get users that have driven this time. - $st = $pdo->prepare("SELECT user FROM records WHERE track = :track AND best = :best ORDER BY LOWER(user)"); - $st->bindParam(':track', $track, PDO::PARAM_STR); - $st->bindParam(':best', $bestTime, PDO::PARAM_INT); - $st->execute(); - $users = $st->fetchAll(PDO::FETCH_COLUMN, 0); - //print_r($users); - - if ($trackSet == "Summer 2020") { - if ($i <= 5) { - $tableColorClass = " class='whiteTracks'"; - } else if ($i <= 10) { - $tableColorClass = " class='greenTracks'"; - } else if ($i <= 15) { - $tableColorClass = " class='blueTracks'"; - } else if ($i <= 20) { - $tableColorClass = " class='redTracks'"; - } else if ($i <= 25) { - $tableColorClass = " class='blackTracks'"; - } - } else { - $tableColorClass = ""; - } -?> > - - - -".($bestTimeByUser[0] / 1000.0)."s\n"; - echo " \n"; - echo " \n"; - echo " \n"; - } else { - echo " \n"; - echo " \n"; - echo " \n"; - echo " \n"; - } - } -?> - -getMessage()); - } -?> -
TrackBest timeDriven byAbsolute deltaRelative delta (%)".htmlspecialchars($selectedUser)."'s rank
s".sprintf("%.3f", $bestTimeByUser[0] / 1000.0 - $bestTime / 1000.0)."s".sprintf("%.1f", $bestTimeByUser[0] / $bestTime * 100)."%".$bestTimeByUser[1]."----
- -".htmlspecialchars($trackSet)." - Total time per user"; ?> - - - - - - -setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - $st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count = 25 ORDER BY count DESC, total_time ASC"); - $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); - $st->execute(); - while ($row = $st->fetch()) { - //print_r($row); -?> - - - -prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count < 25 ORDER BY count DESC, total_time ASC"); - $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); - $st->execute(); - while ($row = $st->fetch()) { - //print_r($row); -?> - - - -getMessage()); - } - ?> -
UserTotal time
s
∞s
- - - - - trackmania-records - - - - - - -
-

trackmania-records

- -No records have been uploaded yet...

"; - } -?> - -

Upload instructions

- -

To upload your Trackmania 2020 records to this page, follow these instructions:

- -
    -
  • Download Python 3 from python.org and install it: https://www.python.org/downloads/
  • -
  • Open a shell/terminal window (cmd.exe or PowerShell)
  • -
  • Install the upload tool by executing this command:
    - pip3 install --upgrade upload-tm-records
  • -
  • Now you can always run the following command to upload your latest records to this server:
    - upload-tm-records.exe
  • -
- -
- -

trackmania-records is opensource: github.com/rsnitsch/trackmania-records

-
- + $bestTime['best']) { + $rank++; + } + } + + return null; + } + + function tableForTrackSet($trackSet, $selectedUser) { + if ($trackSet == "Training") + $count = 25; + else if ($trackSet == "Summer 2020" or $trackSet == "Fall 2020") { + $count = 25; + } else { + throw Exception("Unknown track set"); + } + + echo "

".htmlspecialchars($trackSet)." - Records

"; +?> + + + + + + +".htmlspecialchars($selectedUser)."'s time\n"; + echo " \n"; + echo " \n"; + echo " \n"; + } +?> + +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + + for ($i = 1; $i <= 25; $i++) { + $track = sprintf("$trackSet - %02d", $i); + + // Determine best time for track. + $st = $pdo->prepare("SELECT user, best FROM records WHERE track = :track ORDER BY best ASC"); + $st->bindParam(':track', $track, PDO::PARAM_STR); + $st->execute(); + $bestTimes = $st->fetchAll(); + //print_r($bestTimes); + $bestTime = $bestTimes[0]['best']; + + // Get users that have driven this time. + $st = $pdo->prepare("SELECT user FROM records WHERE track = :track AND best = :best ORDER BY LOWER(user)"); + $st->bindParam(':track', $track, PDO::PARAM_STR); + $st->bindParam(':best', $bestTime, PDO::PARAM_INT); + $st->execute(); + $users = $st->fetchAll(PDO::FETCH_COLUMN, 0); + //print_r($users); + + if ($trackSet == "Summer 2020" or $trackSet == "Fall 2020") { + if ($i <= 5) { + $tableColorClass = " class='whiteTracks'"; + } else if ($i <= 10) { + $tableColorClass = " class='greenTracks'"; + } else if ($i <= 15) { + $tableColorClass = " class='blueTracks'"; + } else if ($i <= 20) { + $tableColorClass = " class='redTracks'"; + } else if ($i <= 25) { + $tableColorClass = " class='blackTracks'"; + } + } else { + $tableColorClass = ""; + } +?> > + + + +".($bestTimeByUser[0] / 1000.0)."s\n"; + echo " \n"; + echo " \n"; + echo " \n"; + } else { + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + } + } +?> + +getMessage()); + } +?> +
TrackBest timeDriven byAbsolute deltaRelative delta (%)".htmlspecialchars($selectedUser)."'s rank
s".sprintf("%.3f", $bestTimeByUser[0] / 1000.0 - $bestTime / 1000.0)."s".sprintf("%.1f", $bestTimeByUser[0] / $bestTime * 100)."%".$bestTimeByUser[1]."----
+ +".htmlspecialchars($trackSet)." - Total time per user"; ?> + + + + + + +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count = 25 ORDER BY count DESC, total_time ASC"); + $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); + $st->execute(); + while ($row = $st->fetch()) { + //print_r($row); +?> + + + +prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count < 25 ORDER BY count DESC, total_time ASC"); + $st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR); + $st->execute(); + while ($row = $st->fetch()) { + //print_r($row); +?> + + + +getMessage()); + } + ?> +
UserTotal time
s
∞s
+ + + + + trackmania-records + + + + + + +
+

trackmania-records

+ +No records have been uploaded yet...

"; + } +?> + +

Upload instructions

+ +

To upload your Trackmania 2020 records to this page, follow these instructions:

+ +
    +
  • Download Python 3 from python.org and install it: https://www.python.org/downloads/
  • +
  • Open a shell/terminal window (cmd.exe or PowerShell)
  • +
  • Install the upload tool by executing this command:
    + pip3 install --upgrade upload-tm-records
  • +
  • Now you can always run the following command to upload your latest records to this server:
    + upload-tm-records.exe
  • +
+ +
+ +

trackmania-records is opensource: github.com/rsnitsch/trackmania-records

+
+ \ No newline at end of file From ce37aa543f420e93164a16f221fbbd66696ecde1 Mon Sep 17 00:00:00 2001 From: Robert Nitsch Date: Sun, 4 Oct 2020 17:48:02 +0200 Subject: [PATCH 15/15] Set version to 1.0.0 --- client/setup.py | 204 ++++++++++++++++---------------- client/src/upload_tm_records.py | 2 +- server/html/upload.php | 138 ++++++++++----------- 3 files changed, 172 insertions(+), 172 deletions(-) diff --git a/client/setup.py b/client/setup.py index 3ad7022..9e9685c 100644 --- a/client/setup.py +++ b/client/setup.py @@ -1,102 +1,102 @@ -import codecs -import os.path -import pathlib -from setuptools import setup, find_packages - -def read(rel_path): - here = os.path.abspath(os.path.dirname(__file__)) - with codecs.open(os.path.join(here, rel_path), 'r') as fp: - return fp.read() - -def get_version(rel_path): - for line in read(rel_path).splitlines(): - if line.startswith('__version__'): - delim = '"' if '"' in line else "'" - return line.split(delim)[1] - else: - raise RuntimeError("Unable to find version string.") - -here = pathlib.Path(__file__).parent.resolve() - -long_description = (here / 'README.md').read_text(encoding='utf-8') - -setup( - name='upload-tm-records', - # https://www.python.org/dev/peps/pep-0440/ - version=get_version('src/upload_tm_records.py'), - description='Upload your trackmania records to a trackmania-records server!', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/rsnitsch/trackmania-records', - author='Robert Nitsch', - author_email='mail@robertnitsch.de', - # For a list of valid classifiers, see https://pypi.org/classifiers/ - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: End Users/Desktop', - 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', - 'Topic :: Games/Entertainment', - - # Specify the Python versions you support here. In particular, ensure - # that you indicate you support Python 3. These classifiers are *not* - # checked by 'pip install'. See instead 'python_requires' below. - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3 :: Only', - ], - - # This field adds keywords for your project which will appear on the - # project page. What does your project relate to? - # - # Note that this is a list of additional keywords, separated - # by commas, to be used to assist searching for the distribution in a - # larger catalog. - keywords='trackmania, gaming', # Optional - - package_dir={'': 'src'}, - - # You can just specify package directories manually here if your project is - # simple. Or you can use find_packages(). - # - # Alternatively, if you just want to distribute a single Python file, use - # the `py_modules` argument instead as follows, which will expect a file - # called `my_module.py` to exist: - # - py_modules=["upload_tm_records"], - # - #packages=find_packages(where='src'), # Required - - # Specify which Python versions you support. In contrast to the - # 'Programming Language' classifiers above, 'pip install' will check this - # and refuse to install the project if the version does not match. See - # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires - python_requires='>=3.7, <4', - - # This field lists other packages that your project depends on to run. - # Any package you put here will be installed by pip when your project is - # installed, so they must be valid existing projects. - # - # For an analysis of "install_requires" vs pip's requirements files see: - # https://packaging.python.org/en/latest/requirements.html - install_requires=['requests'], # Optional - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # `pip` to create the appropriate form of executable for the target - # platform. - # - # For example, the following would provide a command called `sample` which - # executes the function `main` from this package when invoked: - entry_points={ # Optional - 'console_scripts': [ - 'upload-tm-records=upload_tm_records:main', - ], - }, - - project_urls={ # Optional - 'Bug Reports': 'https://github.com/rsnitsch/trackmania-records/issues', - 'Source': 'https://github.com/rsnitsch/trackmania-records', - }, -) +import codecs +import os.path +import pathlib +from setuptools import setup, find_packages + +def read(rel_path): + here = os.path.abspath(os.path.dirname(__file__)) + with codecs.open(os.path.join(here, rel_path), 'r') as fp: + return fp.read() + +def get_version(rel_path): + for line in read(rel_path).splitlines(): + if line.startswith('__version__'): + delim = '"' if '"' in line else "'" + return line.split(delim)[1] + else: + raise RuntimeError("Unable to find version string.") + +here = pathlib.Path(__file__).parent.resolve() + +long_description = (here / 'README.md').read_text(encoding='utf-8') + +setup( + name='upload-tm-records', + # https://www.python.org/dev/peps/pep-0440/ + version=get_version('src/upload_tm_records.py'), + description='Upload your trackmania records to a trackmania-records server!', + long_description=long_description, + long_description_content_type='text/markdown', + url='https://github.com/rsnitsch/trackmania-records', + author='Robert Nitsch', + author_email='mail@robertnitsch.de', + # For a list of valid classifiers, see https://pypi.org/classifiers/ + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: End Users/Desktop', + 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', + 'Topic :: Games/Entertainment', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate you support Python 3. These classifiers are *not* + # checked by 'pip install'. See instead 'python_requires' below. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3 :: Only', + ], + + # This field adds keywords for your project which will appear on the + # project page. What does your project relate to? + # + # Note that this is a list of additional keywords, separated + # by commas, to be used to assist searching for the distribution in a + # larger catalog. + keywords='trackmania, gaming', # Optional + + package_dir={'': 'src'}, + + # You can just specify package directories manually here if your project is + # simple. Or you can use find_packages(). + # + # Alternatively, if you just want to distribute a single Python file, use + # the `py_modules` argument instead as follows, which will expect a file + # called `my_module.py` to exist: + # + py_modules=["upload_tm_records"], + # + #packages=find_packages(where='src'), # Required + + # Specify which Python versions you support. In contrast to the + # 'Programming Language' classifiers above, 'pip install' will check this + # and refuse to install the project if the version does not match. See + # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires + python_requires='>=3.7, <4', + + # This field lists other packages that your project depends on to run. + # Any package you put here will be installed by pip when your project is + # installed, so they must be valid existing projects. + # + # For an analysis of "install_requires" vs pip's requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['requests'], # Optional + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # `pip` to create the appropriate form of executable for the target + # platform. + # + # For example, the following would provide a command called `sample` which + # executes the function `main` from this package when invoked: + entry_points={ # Optional + 'console_scripts': [ + 'upload-tm-records=upload_tm_records:main', + ], + }, + + project_urls={ # Optional + 'Bug Reports': 'https://github.com/rsnitsch/trackmania-records/issues', + 'Source': 'https://github.com/rsnitsch/trackmania-records', + }, +) diff --git a/client/src/upload_tm_records.py b/client/src/upload_tm_records.py index ffa7227..30fc234 100644 --- a/client/src/upload_tm_records.py +++ b/client/src/upload_tm_records.py @@ -8,7 +8,7 @@ import requests -__version__ = '1.0.0b1' +__version__ = '1.0.0' logger = logging.getLogger(__name__) diff --git a/server/html/upload.php b/server/html/upload.php index d5c623b..811b6f1 100644 --- a/server/html/upload.php +++ b/server/html/upload.php @@ -1,69 +1,69 @@ -setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - $commands = ['CREATE TABLE IF NOT EXISTS records ( - game TEXT NOT NULL, - user TEXT NOT NULL, - track TEXT NOT NULL, - best INTEGER NOT NULL, - PRIMARY KEY (game, user, track) - )']; - - foreach ($commands as $command) { - $pdo->exec($command); - } - - foreach ($records as $record) { - //print_r($record); - - $user = $record['user']; - $track = $record['track']; - $best = intval($record['best']); - - // Delete previous record. - $st = $pdo->prepare('DELETE FROM records WHERE user = :user AND track = :track'); - $st->bindParam(':user', $user, PDO::PARAM_STR); - $st->bindParam(':track', $track, PDO::PARAM_STR); - $st->execute(); - - // Add new record. - $st = $pdo->prepare("INSERT INTO records (game, user, track, best) VALUES ('Trackmania 2020', :user, :track, :best)"); - $st->bindParam(':user', $user, PDO::PARAM_STR); - $st->bindParam(':track', $track, PDO::PARAM_STR); - $st->bindParam(':best', $best, PDO::PARAM_INT); - $st->execute(); - } - - echo "Success!"; - } catch (PDOException $e) { - http_response_code(500); - die('Database error: '.$e->getMessage()); - } +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $commands = ['CREATE TABLE IF NOT EXISTS records ( + game TEXT NOT NULL, + user TEXT NOT NULL, + track TEXT NOT NULL, + best INTEGER NOT NULL, + PRIMARY KEY (game, user, track) + )']; + + foreach ($commands as $command) { + $pdo->exec($command); + } + + foreach ($records as $record) { + //print_r($record); + + $user = $record['user']; + $track = $record['track']; + $best = intval($record['best']); + + // Delete previous record. + $st = $pdo->prepare('DELETE FROM records WHERE user = :user AND track = :track'); + $st->bindParam(':user', $user, PDO::PARAM_STR); + $st->bindParam(':track', $track, PDO::PARAM_STR); + $st->execute(); + + // Add new record. + $st = $pdo->prepare("INSERT INTO records (game, user, track, best) VALUES ('Trackmania 2020', :user, :track, :best)"); + $st->bindParam(':user', $user, PDO::PARAM_STR); + $st->bindParam(':track', $track, PDO::PARAM_STR); + $st->bindParam(':best', $best, PDO::PARAM_INT); + $st->execute(); + } + + echo "Success!"; + } catch (PDOException $e) { + http_response_code(500); + die('Database error: '.$e->getMessage()); + }