The official website for the open-source compatibility layer fpPS4
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

massive code changes :3

rewrote all scripts and added homebrew support.

+1384 -2216
-2
.gitattributes
··· 1 - # Auto detect text files and perform LF normalization 2 - * text=auto
+6 -13
.gitignore
··· 1 - /.htpasswd 1 + /_config 2 2 /.vscode 3 - /config 4 - /logs 5 - /public_ftp 6 - /stats 7 - public_html/beta 8 - public_html/cgi-bin 9 - public_html/.htaccess 10 - public_html/ads.txt 11 - public_html/images/Thumbs.db 12 - public_html/images/CUSA 13 - public_html/images/HOMEBREW 14 - public_html/scripts/HBstore.db 3 + /public_html/_images/CUSA 4 + /public_html/_images/HB 5 + /public_html/_images/TEST 6 + /public_html/.htaccess 7 + /public_html/.user.ini
+119
document_errors/403.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="utf-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 + <title>Access Denied</title> 7 + <style> 8 + body { 9 + background-color: #f5f5f5; 10 + margin-top: 8%; 11 + color: #5d5d5d; 12 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, 13 + "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", 14 + "Noto Color Emoji"; 15 + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75); 16 + text-align: center; 17 + } 18 + 19 + h1 { 20 + font-size: 2.45em; 21 + font-weight: 700; 22 + color: #5d5d5d; 23 + letter-spacing: -0.02em; 24 + margin-bottom: 30px; 25 + margin-top: 30px; 26 + } 27 + 28 + .container { 29 + width: 100%; 30 + margin-right: auto; 31 + margin-left: auto; 32 + } 33 + 34 + .animate__animated { 35 + animation-duration: 1s; 36 + animation-fill-mode: both; 37 + } 38 + 39 + .animate__fadeIn { 40 + animation-name: fadeIn; 41 + } 42 + 43 + .info { 44 + color: #5594cf; 45 + fill: #5594cf; 46 + } 47 + 48 + .error { 49 + color: #c92127; 50 + fill: #c92127; 51 + } 52 + 53 + .warning { 54 + color: #ffcc33; 55 + fill: #ffcc33; 56 + } 57 + 58 + .success { 59 + color: #5aba47; 60 + fill: #5aba47; 61 + } 62 + 63 + .icon-large { 64 + height: 132px; 65 + width: 132px; 66 + } 67 + 68 + .description-text { 69 + color: #707070; 70 + letter-spacing: -0.01em; 71 + font-size: 1.25em; 72 + line-height: 20px; 73 + } 74 + 75 + .footer { 76 + margin-top: 40px; 77 + font-size: 0.7em; 78 + } 79 + 80 + .animate__delay-1s { 81 + animation-delay: 1s; 82 + } 83 + 84 + @keyframes fadeIn { 85 + from { 86 + opacity: 0; 87 + } 88 + to { 89 + opacity: 1; 90 + } 91 + } 92 + </style> 93 + </head> 94 + <body> 95 + <div class="container"> 96 + <div class="row"> 97 + <div class="col"> 98 + <div class="animate__animated animate__fadeIn"> 99 + <svg 100 + class="error icon-large fa-times-circle" 101 + xmlns="http://www.w3.org/2000/svg" 102 + viewBox="0 0 512 512" 103 + > 104 + <path 105 + d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z" 106 + ></path> 107 + </svg> 108 + </div> 109 + <h1 class="animate__animated animate__fadeIn">Access Denied</h1> 110 + <div class="description-text animate__animated animate__fadeIn animate__delay-1s"> 111 + <p>You do not have permission to view this page.</p> 112 + <p>Please check your credentials and try again.</p> 113 + <section class="footer"><strong>Error Code:</strong> 403</section> 114 + </div> 115 + </div> 116 + </div> 117 + </div> 118 + </body> 119 + </html>
+12
document_errors/404.html
··· 1 + <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 + <HTML><HEAD> 3 + <TITLE>404 :/</TITLE> 4 + <style>@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;500&display=swap');</style> 5 + <link rel="icon" href="/_images/fpPS4Logo.png" type="image/png"> 6 + <meta name="robots" content="noindex"> 7 + </HEAD><BODY style="background-color: #0e141b; color: white; font-family: 'Rubik', sans-serif; text-align: center;"> 8 + <H1>404: Not Found :/</H1> 9 + <pr style="font-size: medium;">The requested URL</span> was not found on this server.</pre> 10 + <HR> 11 + <h1><span style="color: #f0e74a;">fp</span>PS4.net</h1> 12 + </BODY></HTML>
+119
document_errors/410.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="utf-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 + <title>Resource is Gone</title> 7 + <style> 8 + body { 9 + background-color: #f5f5f5; 10 + margin-top: 8%; 11 + color: #5d5d5d; 12 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, 13 + "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", 14 + "Noto Color Emoji"; 15 + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75); 16 + text-align: center; 17 + } 18 + 19 + h1 { 20 + font-size: 2.45em; 21 + font-weight: 700; 22 + color: #5d5d5d; 23 + letter-spacing: -0.02em; 24 + margin-bottom: 30px; 25 + margin-top: 30px; 26 + } 27 + 28 + .container { 29 + width: 100%; 30 + margin-right: auto; 31 + margin-left: auto; 32 + } 33 + 34 + .animate__animated { 35 + animation-duration: 1s; 36 + animation-fill-mode: both; 37 + } 38 + 39 + .animate__fadeIn { 40 + animation-name: fadeIn; 41 + } 42 + 43 + .info { 44 + color: #5594cf; 45 + fill: #5594cf; 46 + } 47 + 48 + .error { 49 + color: #c92127; 50 + fill: #c92127; 51 + } 52 + 53 + .warning { 54 + color: #ffcc33; 55 + fill: #ffcc33; 56 + } 57 + 58 + .success { 59 + color: #5aba47; 60 + fill: #5aba47; 61 + } 62 + 63 + .icon-large { 64 + height: 132px; 65 + width: 132px; 66 + } 67 + 68 + .description-text { 69 + color: #707070; 70 + letter-spacing: -0.01em; 71 + font-size: 1.25em; 72 + line-height: 20px; 73 + } 74 + 75 + .footer { 76 + margin-top: 40px; 77 + font-size: 0.7em; 78 + } 79 + 80 + .animate__delay-1s { 81 + animation-delay: 1s; 82 + } 83 + 84 + @keyframes fadeIn { 85 + from { 86 + opacity: 0; 87 + } 88 + to { 89 + opacity: 1; 90 + } 91 + } 92 + </style> 93 + </head> 94 + <body> 95 + <div class="container"> 96 + <div class="row"> 97 + <div class="col"> 98 + <div class="animate__animated animate__fadeIn"> 99 + <svg 100 + class="info icon-large fa-sign-out-alt" 101 + xmlns="http://www.w3.org/2000/svg" 102 + viewBox="0 0 512 512" 103 + > 104 + <path 105 + d="M272 112v51.6h-96c-26.5 0-48 21.5-48 48v88.6c0 26.5 21.5 48 48 48h96v51.6c0 42.6 51.7 64.2 81.9 33.9l144-143.9c18.7-18.7 18.7-49.1 0-67.9l-144-144C323.8 48 272 69.3 272 112zm192 144L320 400v-99.7H176v-88.6h144V112l144 144zM96 64h84c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H96c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h84c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H96c-53 0-96-43-96-96V160c0-53 43-96 96-96z" 106 + ></path> 107 + </svg> 108 + </div> 109 + <h1 class="animate__animated animate__fadeIn">Resource is Gone</h1> 110 + <div class="description-text animate__animated animate__fadeIn animate__delay-1s"> 111 + <p>Oops! The requested resource is no longer available.</p> 112 + <p>Please check the address and try again.</p> 113 + <section class="footer"><strong>Error Code:</strong> 410</section> 114 + </div> 115 + </div> 116 + </div> 117 + </div> 118 + </body> 119 + </html>
+122
document_errors/50x.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="utf-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 + <title>Internal Server Error</title> 7 + <style> 8 + body { 9 + background-color: #f5f5f5; 10 + margin-top: 8%; 11 + color: #5d5d5d; 12 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, 13 + "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", 14 + "Noto Color Emoji"; 15 + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75); 16 + text-align: center; 17 + } 18 + 19 + h1 { 20 + font-size: 2.45em; 21 + font-weight: 700; 22 + color: #5d5d5d; 23 + letter-spacing: -0.02em; 24 + margin-bottom: 30px; 25 + margin-top: 30px; 26 + } 27 + 28 + .container { 29 + width: 100%; 30 + margin-right: auto; 31 + margin-left: auto; 32 + } 33 + 34 + .animate__animated { 35 + animation-duration: 1s; 36 + animation-fill-mode: both; 37 + } 38 + 39 + .animate__fadeIn { 40 + animation-name: fadeIn; 41 + } 42 + 43 + .info { 44 + color: #5594cf; 45 + fill: #5594cf; 46 + } 47 + 48 + .error { 49 + color: #c92127; 50 + fill: #c92127; 51 + } 52 + 53 + .warning { 54 + color: #ffcc33; 55 + fill: #ffcc33; 56 + } 57 + 58 + .success { 59 + color: #5aba47; 60 + fill: #5aba47; 61 + } 62 + 63 + .icon-large { 64 + height: 132px; 65 + width: 132px; 66 + } 67 + 68 + .description-text { 69 + color: #707070; 70 + letter-spacing: -0.01em; 71 + font-size: 1.25em; 72 + line-height: 20px; 73 + } 74 + 75 + .footer { 76 + margin-top: 40px; 77 + font-size: 0.7em; 78 + } 79 + 80 + .animate__delay-1s { 81 + animation-delay: 1s; 82 + } 83 + 84 + @keyframes fadeIn { 85 + from { 86 + opacity: 0; 87 + } 88 + to { 89 + opacity: 1; 90 + } 91 + } 92 + </style> 93 + </head> 94 + <body> 95 + <div class="container"> 96 + <div class="row"> 97 + <div class="col"> 98 + <div class="animate__animated animate__fadeIn"> 99 + <svg 100 + class="warning icon-large fa-exclamation-triangle" 101 + xmlns="http://www.w3.org/2000/svg" 102 + viewBox="0 0 576 512" 103 + > 104 + <path 105 + d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z" 106 + ></path> 107 + </svg> 108 + </div> 109 + <h1 class="animate__animated animate__fadeIn">Internal Server Error</h1> 110 + <div class="description-text animate__animated animate__fadeIn animate__delay-1s"> 111 + <p>Oops! Something went wrong.</p> 112 + <p> 113 + The server encountered an internal error or misconfiguration and was unable to 114 + complete your request. 115 + </p> 116 + <section class="footer"><strong>Error Code:</strong> 500</section> 117 + </div> 118 + </div> 119 + </div> 120 + </div> 121 + </body> 122 + </html>
private_html

This is a binary file and will not be displayed.

-301
public_html/400.shtml
··· 1 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 - <HTML><HEAD> 3 - <TITLE>400 Bad Request</TITLE> 4 - </HEAD><BODY> 5 - <H1>Bad Request</H1> 6 - There was an error in your request. 7 - <HR> 8 - <I><!--#echo var="HTTP_HOST" --></I> 9 - </BODY></HTML> 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 118 - 119 - 120 - 121 - 122 - 123 - 124 - 125 - 126 - 127 - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - 148 - 149 - 150 - 151 - 152 - 153 - 154 - 155 - 156 - 157 - 158 - 159 - 160 - 161 - 162 - 163 - 164 - 165 - 166 - 167 - 168 - 169 - 170 - 171 - 172 - 173 - 174 - 175 - 176 - 177 - 178 - 179 - 180 - 181 - 182 - 183 - 184 - 185 - 186 - 187 - 188 - 189 - 190 - 191 - 192 - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 - 203 - 204 - 205 - 206 - 207 - 208 - 209 - 210 - 211 - 212 - 213 - 214 - 215 - 216 - 217 - 218 - 219 - 220 - 221 - 222 - 223 - 224 - 225 - 226 - 227 - 228 - 229 - 230 - 231 - 232 - 233 - 234 - 235 - 236 - 237 - 238 - 239 - 240 - 241 - 242 - 243 - 244 - 245 - 246 - 247 - 248 - 249 - 250 - 251 - 252 - 253 - 254 - 255 - 256 - 257 - 258 - 259 - 260 - 261 - 262 - 263 - 264 - 265 - 266 - 267 - 268 - 269 - 270 - 271 - 272 - 273 - 274 - 275 - 276 - 277 - 278 - 279 - 280 - 281 - 282 - 283 - 284 - 285 - 286 - 287 - 288 - 289 - 290 - 291 - 292 - 293 - 294 - 295 - 296 - 297 - 298 - 299 - 300 - 301 -
-89
public_html/401.shtml
··· 1 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 - <HTML><HEAD> 3 - <TITLE>401 Authorization Required</TITLE> 4 - </HEAD><BODY> 5 - <H1>Authorization Required</H1> 6 - This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required. 7 - <HR> 8 - <I><!--#echo var="HTTP_HOST" --></I> 9 - </BODY></HTML> 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 -
-257
public_html/403.shtml
··· 1 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 - <HTML><HEAD> 3 - <TITLE>403 Forbidden</TITLE> 4 - </HEAD><BODY> 5 - <H1>Forbidden</H1> 6 - You don't have permission to access <!--#echo var="REQUEST_URI" --> on this server. 7 - <HR> 8 - <I><!--#echo var="HTTP_HOST" --></I> 9 - </BODY></HTML> 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 118 - 119 - 120 - 121 - 122 - 123 - 124 - 125 - 126 - 127 - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - 148 - 149 - 150 - 151 - 152 - 153 - 154 - 155 - 156 - 157 - 158 - 159 - 160 - 161 - 162 - 163 - 164 - 165 - 166 - 167 - 168 - 169 - 170 - 171 - 172 - 173 - 174 - 175 - 176 - 177 - 178 - 179 - 180 - 181 - 182 - 183 - 184 - 185 - 186 - 187 - 188 - 189 - 190 - 191 - 192 - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 - 203 - 204 - 205 - 206 - 207 - 208 - 209 - 210 - 211 - 212 - 213 - 214 - 215 - 216 - 217 - 218 - 219 - 220 - 221 - 222 - 223 - 224 - 225 - 226 - 227 - 228 - 229 - 230 - 231 - 232 - 233 - 234 - 235 - 236 - 237 - 238 - 239 - 240 - 241 - 242 - 243 - 244 - 245 - 246 - 247 - 248 - 249 - 250 - 251 - 252 - 253 - 254 - 255 - 256 - 257 -
-12
public_html/404.php
··· 1 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 - <HTML><HEAD> 3 - <TITLE>404 :/</TITLE> 4 - <style>@import url('https://fonts.googleapis.com/css2?family=Montserrat');</style> 5 - <link rel="icon" href="https://fpps4.net/images/fpPS4Logo.png" type="image/png"> 6 - <meta name="robots" content="noindex"> 7 - </HEAD><BODY style="background-color: #0e141b; color: white; font-family: 'Montserrat', sans-serif; text-align: center;"> 8 - <H1>404: Not Found :/</H1> 9 - <pr style="font-size: medium;">The requested URL <span style="color: #f0e74a"><?php echo htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES); ?></span> was not found on this server.</pre> 10 - <HR> 11 - <h1><span style="color: #f0e74a;">fp</span>PS4.net</h1> 12 - </BODY></HTML>
-216
public_html/500.shtml
··· 1 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 2 - <HTML><HEAD> 3 - <TITLE>500 Internal Server Error</TITLE> 4 - </HEAD><BODY> 5 - <H1>Internal Server Error</H1> 6 - The server encountered an internal error or misconfiguration and was unable to complete your request 7 - <HR> 8 - <I><!--#echo var="HTTP_HOST" --></I> 9 - </BODY></HTML> 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 57 - 58 - 59 - 60 - 61 - 62 - 63 - 64 - 65 - 66 - 67 - 68 - 69 - 70 - 71 - 72 - 73 - 74 - 75 - 76 - 77 - 78 - 79 - 80 - 81 - 82 - 83 - 84 - 85 - 86 - 87 - 88 - 89 - 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 - 98 - 99 - 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 118 - 119 - 120 - 121 - 122 - 123 - 124 - 125 - 126 - 127 - 128 - 129 - 130 - 131 - 132 - 133 - 134 - 135 - 136 - 137 - 138 - 139 - 140 - 141 - 142 - 143 - 144 - 145 - 146 - 147 - 148 - 149 - 150 - 151 - 152 - 153 - 154 - 155 - 156 - 157 - 158 - 159 - 160 - 161 - 162 - 163 - 164 - 165 - 166 - 167 - 168 - 169 - 170 - 171 - 172 - 173 - 174 - 175 - 176 - 177 - 178 - 179 - 180 - 181 - 182 - 183 - 184 - 185 - 186 - 187 - 188 - 189 - 190 - 191 - 192 - 193 - 194 - 195 - 196 - 197 - 198 - 199 - 200 - 201 - 202 - 203 - 204 - 205 - 206 - 207 - 208 - 209 - 210 - 211 - 212 - 213 - 214 - 215 - 216 -
+1
public_html/_images/close.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M249-201.261 201.261-249l231-231-231-231L249-758.739l231 231 231-231L758.739-711l-231 231 231 231L711-201.261l-231-231-231 231Z" fill="black"/></svg>
+1
public_html/_images/discord.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><path d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z" fill="black"/></svg>
+1
public_html/_images/menu.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M114.022-231.152v-68.37h732.196v68.37H114.022Zm0-214.783v-68.13h732.196v68.13H114.022Zm0-214.543v-68.37h732.196v68.37H114.022Z" fill="black"/></svg>
+104
public_html/_parts/required.js
··· 1 + let lightTheme = false; 2 + 3 + const lightThemeCookie = checkCookies("lightTheme", "false"); 4 + if (lightThemeCookie === "true") { 5 + lightTheme = true; 6 + document.body.classList.toggle("lightMode"); 7 + } 8 + //- Checks cookies 9 + 10 + function LightModeIconChange() { 11 + if (lightTheme === true) { 12 + document.getElementById("lightModeIcon").style.display = "flex"; 13 + document.getElementById("darkModeIcon").style.display = "none"; 14 + } else { 15 + document.getElementById("darkModeIcon").style.opacity = "1"; 16 + } 17 + } 18 + 19 + // Cookies 20 + function setCookie(name, value) { 21 + var date = new Date(); 22 + date.setMonth(date.getMonth() + 3); 23 + var expires = "; expires=" + date.toUTCString(); 24 + document.cookie = name + "=" + value + expires + "; path=/"; 25 + } 26 + 27 + function checkCookies(name, defaultValue) { 28 + return document.cookie.split("; ").find(c => c.startsWith(name + "="))?.split("=")[1] ?? defaultValue; // if cookie doesnt exist use the default value 29 + } 30 + 31 + function toggleLightMode() { 32 + lightTheme = !lightTheme; 33 + setCookie("lightTheme", lightTheme); 34 + document.body.classList.toggle("lightMode"); 35 + var x = document.getElementById("darkModeIcon") 36 + var y = document.getElementById("lightModeIcon") 37 + if (y.style.display === "none" || y.style.display == '') { 38 + y.style.display = "flex"; 39 + x.style.display = "none"; 40 + } else { 41 + x.style.opacity = "1"; 42 + x.style.display = "flex"; 43 + y.style.display = "none"; 44 + }; 45 + }; 46 + 47 + function toggleMenu() { 48 + // var x = document.getElementById("overlay"); 49 + var y = document.getElementById("close-icon") 50 + var z = document.getElementById("menu-icon") 51 + console.log('pretend like you see a menu') 52 + if (y.style.display === "none" || y.style.display == '') { 53 + // x.style.display = "flex"; 54 + y.style.display = "flex"; 55 + z.style.display = "none"; 56 + setTimeout(function() { 57 + // x.style.opacity = 1; 58 + }, 50); 59 + } else { 60 + // x.style.opacity = 0; 61 + y.style.display = "none"; 62 + z.style.display = "flex"; 63 + setTimeout(function() { 64 + // x.style.display = "none"; 65 + }, 300); 66 + }; 67 + }; 68 + 69 + // update footer position 70 + function updateFooter() { 71 + const viewportHeight = window.innerHeight; 72 + const bodyHeight = document.body.clientHeight; 73 + if (bodyHeight < viewportHeight) { 74 + document.getElementById('footer').style.position = 'fixed'; 75 + } else { 76 + document.getElementById('footer').style = ''; 77 + } 78 + } 79 + 80 + // Adjust screen size for mobile and 4k monitors for some reason 81 + function adjustScreenSize() { 82 + var screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 83 + var referenceWidth = 2000; 84 + var referenceFontSize = 16; 85 + var phoneReferenceWidth = 550; 86 + 87 + if (screenWidth >= referenceWidth) { // 2000 ++ 88 + var fontSize = (screenWidth / referenceWidth) * referenceFontSize; 89 + document.documentElement.style.width = ""; 90 + document.documentElement.style.fontSize = fontSize + 'px'; 91 + 92 + } else if (screenWidth >= phoneReferenceWidth) { // 550 - 2000 93 + document.documentElement.style.fontSize = referenceFontSize + 'px'; 94 + document.documentElement.style.width = ""; 95 + 96 + } else { // -- 550 97 + var fontSize = (screenWidth / phoneReferenceWidth) * referenceFontSize; 98 + document.documentElement.style.width = screenWidth + "px"; 99 + var viewport = document.querySelector('meta[name="viewport"]'); 100 + viewport.content = "initial-scale=1"; 101 + document.documentElement.style.zoom = "1"; 102 + document.documentElement.style.fontSize = fontSize + 'px'; 103 + } 104 + }
+189
public_html/_scripts/search.php
··· 1 + <?php 2 + // V2 or something idk 3 + 4 + $startTime = microtime(true); // timer 5 + 6 + /// connecting to database 7 + $dir = dirname(__DIR__, 2); 8 + require_once "$dir/_config/config.php"; // import config file 9 + 10 + $host = DATABASE_HOST; 11 + $database = DATABASE_NAME; 12 + $username = DATABASE_USERNAME; 13 + $password = DATABASE_PASSWORD; 14 + try { 15 + $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); 16 + } catch (PDOException $e) { 17 + echo "The server got itself into trouble, please try to refresh.<br>"; 18 + } 19 + 20 + /// processing user input 21 + $searchQuery = htmlspecialchars(isset($_GET['q']) ? $_GET['q'] : ""); 22 + $tags = htmlspecialchars(isset($_GET['tag']) ? $_GET['tag'] : ""); 23 + $page = filter_var(isset($_GET['page']) ? $_GET['page'] : 1, FILTER_VALIDATE_INT); 24 + $oldest = filter_var(isset($_GET['oldest']) ? $_GET['oldest'] : false, FILTER_VALIDATE_BOOLEAN); 25 + $giveStats = filter_var(isset($_GET['stats']) ? true : false, FILTER_VALIDATE_BOOLEAN); 26 + 27 + if ($page < 0 || $page === 0) { 28 + $page = 1; 29 + } 30 + 31 + /// defining stuff lmao 32 + $maxResults = (!empty($searchQuery)) ? 10 : 20; 33 + $pageNumber = ($page - 1) * $maxResults; 34 + $sqlQuery = "SELECT * FROM issues"; 35 + $params = array(); 36 + $conditions = array(); 37 + 38 + 39 + /// if there is an search query in the request 40 + if (!empty($searchQuery)) { 41 + $searchQuery = strtolower($searchQuery); 42 + if (strpos($searchQuery, 'cusa') !== false) { 43 + $conditions[] = "code LIKE :searchQuery"; 44 + } else { 45 + $conditions[] = "title LIKE :searchQuery"; 46 + } 47 + $params[':searchQuery'] = $searchQuery . '%'; 48 + } 49 + 50 + 51 + /// if there are tags in the request 52 + if (!empty($tags)) { 53 + $tagFilters = explode(',', $tags); 54 + $tagConditions = []; 55 + $tagParams = []; 56 + 57 + foreach ($tagFilters as $index => $tag) { 58 + $tagParam = ":tagFilter{$index}"; 59 + $tagConditions[] = "(CONCAT(',', tags, ',') LIKE CONCAT('%,', {$tagParam}, ',%'))"; 60 + $tagParams[$tagParam] = "{$tag}"; 61 + } 62 + 63 + if (!empty($tagConditions)) { 64 + $conditions[] = "(" . implode(" OR ", $tagConditions) . ")"; 65 + $params = array_merge($params, $tagParams); 66 + } 67 + } 68 + 69 + if (!empty($conditions)) { 70 + $sqlQuery .= " WHERE " . implode(" AND ", $conditions); 71 + } 72 + 73 + 74 + /// gets the total amount of issues based on the search query 75 + $sqlQueryForTotal = "SELECT COUNT(*) AS total FROM ($sqlQuery) AS totalIssues"; 76 + $stmtTotal = $conn->prepare($sqlQueryForTotal); 77 + 78 + foreach ($params as $param => &$value) { 79 + $stmtTotal->bindParam($param, $value, PDO::PARAM_STR); 80 + } 81 + 82 + $stmtTotal->execute(); 83 + $totalIssuesAmount = $stmtTotal->fetch(PDO::FETCH_ASSOC)['total']; 84 + $totalPages = ceil($totalIssuesAmount / $maxResults); 85 + 86 + 87 + /// forming and executing sql query 88 + $sqlQuery .= " ORDER BY id " . ($oldest ? "ASC" : "DESC"); 89 + $sqlQuery .= " LIMIT :offset, :limit"; 90 + $params[':offset'] = $pageNumber; 91 + $params[':limit'] = $maxResults; 92 + 93 + $stmt = $conn->prepare($sqlQuery); 94 + 95 + foreach ($params as $param => &$value) { 96 + if (is_int($value)) { 97 + $stmt->bindParam($param, $value, PDO::PARAM_INT); 98 + } else { 99 + $stmt->bindParam($param, $value, PDO::PARAM_STR); 100 + } 101 + } 102 + 103 + $stmt->execute(); 104 + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); 105 + 106 + 107 + /// Outputing results 108 + header('Content-Type: application/json'); 109 + 110 + $games = array(); 111 + $stats = array(); 112 + 113 + foreach ($result as $game) { 114 + $cusaCode = $game['code']; 115 + $image = $game['type'] === "HB" ? (file_exists("$dir/public_html/_images/HB/{$game['title']}.avif") ? true : false) : (file_exists("$dir/public_html/_images/CUSA/{$cusaCode}.avif") ? true : false); 116 + $games[] = array( 117 + "id" => $game['id'], 118 + "title" => $game['title'], 119 + "code" => $game['code'], 120 + "type" => $game['type'], 121 + "tag" => $game['tags'], 122 + "upDate" => $game['updatedDate'], 123 + "image" => $image 124 + ); 125 + } 126 + 127 + /// stats on the compatibility list 128 + if ($giveStats === true) { 129 + $availableTags = ['Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; 130 + $tagPercentages = []; 131 + 132 + $naTag = "N/A"; 133 + $stmt = $conn->prepare("SELECT COUNT(*) AS count FROM issues WHERE tags = :tag"); 134 + $stmt->bindParam(':tag', $naTag, PDO::PARAM_STR); 135 + $stmt->execute(); 136 + $naCount = $stmt->fetch(PDO::FETCH_ASSOC)['count']; 137 + 138 + $result = $conn->query("SELECT COUNT(*) FROM issues"); 139 + $total = $result->fetchColumn(); 140 + 141 + $totalIssuesWithoutNA = $total - $naCount; 142 + 143 + foreach ($availableTags as $tag) { 144 + $stmt = $conn->prepare("SELECT COUNT(*) AS count FROM issues WHERE tags = :tag"); 145 + $stmt->bindParam(':tag', $tag, PDO::PARAM_STR); 146 + $stmt->execute(); 147 + 148 + $count = $stmt->fetch(PDO::FETCH_ASSOC)['count']; 149 + $percentage = ($total > 0) ? ($count / $total) * 100 : 0; 150 + $tagPercentages[$tag] = $percentage; 151 + $tagCount[$tag] = $count; 152 + } 153 + 154 + $amount = (100 - array_sum($tagPercentages)) / count($tagPercentages); 155 + 156 + foreach ($availableTags as $tag) { 157 + $percentage = $tagPercentages[$tag]; 158 + $count = $tagCount[$tag]; 159 + $percentage += $amount; 160 + $percentage = round($percentage, 2); 161 + $stats[] = array( 162 + "tag" => $tag, 163 + "percent" => $percentage, 164 + "count" => $count 165 + ); 166 + } 167 + } 168 + 169 + $executionTime = round((microtime(true) - $startTime) * 1000, 2); // Convert to milliseconds 170 + 171 + $info = array( 172 + "issues" => $totalIssuesAmount, 173 + "pages" => $totalPages, 174 + "time" => $executionTime 175 + ); 176 + 177 + $data = array( 178 + "info" => $info, 179 + "games" => $games, 180 + "stats" => $stats, 181 + ); 182 + 183 + 184 + /// end 185 + $jsonData = json_encode($data); 186 + // $jsonData = json_encode($data, JSON_PRETTY_PRINT); 187 + echo $jsonData; 188 + $conn = null; //exit connection 189 + ?>
+336
public_html/_scripts/updater.php
··· 1 + <?php 2 + $startTime = microtime(true); 3 + echo "Started on: " . date("H:i d/m/Y") . "<br><br>"; 4 + $dir = dirname(__DIR__, 2); 5 + require_once "$dir/_config/config.php"; // import config file 6 + 7 + if ((isset($_GET[ARGUMENT_SECRET]) && $_GET[ARGUMENT_SECRET] === ACCESS_SECRET) || (isset($argv[1]) && $argv[1] === ARGUMENT_SECRET)) { 8 + // echo"<style>@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;500&display=swap'); * {font-family: 'Rubik', sans-serif;font-weight: 400;}</style>"; 9 + function ErrorHandler($errLvl, $errMesg, $errFile, $errLine) { 10 + $position = strpos($errMesg, "/"); 11 + $errMesg = $position !== false ? substr($errMesg,0, $position) : $errMesg; // check for an "/" and remove stuff 12 + 13 + switch ($errLvl) { 14 + case E_ERROR || E_USER_ERROR: 15 + $error = "Error: $errMesg [line: $errLine]"; 16 + break; 17 + case E_WARNING || E_USER_WARNING: 18 + $error = "Warning: $errMesg [line: $errLine]"; 19 + break; 20 + case E_NOTICE || E_USER_NOTICE: 21 + $error = "Notice: $errMesg [line: $errLine]"; 22 + break; 23 + default: 24 + $error = "Unknown error: $errMesg [line: $errLine]"; 25 + break; 26 + } 27 + $fullError = "<span style='font-weight: 500;'>Something went wrong => $error </span><br>"; 28 + throw new Exception("$fullError"); 29 + } 30 + set_error_handler("ErrorHandler"); 31 + 32 + $host = DATABASE_HOST; 33 + $database = DATABASE_NAME; 34 + $username = DATABASE_USERNAME; 35 + $password = DATABASE_PASSWORD; 36 + 37 + $githubToken = GITHUB_TOKEN; 38 + $tmdbHash = TMDB_HASH; 39 + $HBheader = stream_context_create(["http" => ["header" => "User-Agent: " . HB_USERAGENT ."\r\n"]]); 40 + 41 + // get homebrew db for images 42 + try { 43 + if (date("i") > 58 || date("i") < 3) { 44 + $response = file_get_contents("https://api.pkg-zone.com/api.php?db_check_hash=true", false, $HBheader); 45 + $hash = json_decode($response)->hash; //get hash from json 46 + $md5Hash = file_exists("$dir/_config/HBstore.db") ? md5_file("$dir/_config/HBstore.db") : "0"; 47 + 48 + if ($hash !== $md5Hash) { 49 + $fileContent = file_get_contents("https://api.pkg-zone.com/store.db", false, $HBheader); 50 + file_put_contents("$dir/_config/HBstore.db", $fileContent); 51 + } 52 + } 53 + } catch (Exception $e) { 54 + print($e); 55 + file_exists("$dir/_config/HBstore.db") ? print("Ignoring for now <br>") : die("Critical error, stopping <br>"); 56 + 57 + } finally {print("Homebrew database download task "); date("i") > 58 || date("i") < 3 ? print("completed! <br>") : print("skipped! <br>");} 58 + 59 + 60 + // database connection and table creation 61 + try { 62 + $homebrewDB = new PDO("sqlite:$dir/_config/HBstore.db"); 63 + $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); 64 + $conn->query("DROP TABLE IF EXISTS newIssues"); 65 + 66 + // creating tables 67 + $sqlQuerys = [ 68 + "CREATE TABLE IF NOT EXISTS issues ( 69 + id INT(5) PRIMARY KEY, 70 + code VARCHAR(10), 71 + title VARCHAR(130), 72 + tags VARCHAR(200), 73 + type VARCHAR(6), 74 + updatedDate VARCHAR(12), 75 + createdDate VARCHAR(12) 76 + )", 77 + "CREATE TABLE IF NOT EXISTS newIssues ( 78 + id INT(5) PRIMARY KEY, 79 + code VARCHAR(10), 80 + title VARCHAR(130), 81 + tags VARCHAR(200), 82 + type VARCHAR(6), 83 + updatedDate VARCHAR(12), 84 + createdDate VARCHAR(12) 85 + )", 86 + "CREATE TABLE IF NOT EXISTS GameSkips ( 87 + code VARCHAR(130) PRIMARY KEY 88 + )" 89 + ]; 90 + 91 + foreach ($sqlQuerys as $sql) { 92 + $conn->exec($sql); 93 + } 94 + 95 + } catch (Exception $e) { 96 + print($e); 97 + die("Critical error, stopping <br>"); 98 + } finally {echo"Database connection and table creation task completed! <br>";} 99 + 100 + 101 + function githubRequest(string $token, int $count, string $url) { 102 + $curl_handle = curl_init(); 103 + curl_setopt($curl_handle, CURLOPT_URL, $url); 104 + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('Accept: application/vnd.github+json', 'Authorization: Bearer '.$token)); 105 + curl_setopt($curl_handle, CURLOPT_USERAGENT, "fpPS4.net"); 106 + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); 107 + $data = curl_exec($curl_handle); 108 + curl_close($curl_handle); 109 + 110 + $count++; 111 + return json_decode($data, true); 112 + } 113 + 114 + function imageDownloader(string $url, $header, string $location) { 115 + $httpsUrl = str_replace('http://', 'https://', $url); 116 + $imageData = file_get_contents($httpsUrl, false, $header); 117 + 118 + $imagick = new Imagick(); 119 + if ($imagick->readImageBlob($imageData)) { 120 + $imageFormat = $imagick->getImageFormat(); 121 + if ($imageFormat == 'JPEG' || $imageFormat == 'PNG') { 122 + $imagick->setImageFormat('avif'); 123 + $imagick->setCompressionQuality(75); 124 + $imagick->setImageProperty('avif:effort', '10'); 125 + $imagick->setImageProperty('avif:speed', '1'); 126 + $imagick->thumbnailImage(256, 256, true); 127 + $imagick->stripImage(); 128 + $imagick->writeImage($location); // save the image 129 + } 130 + } 131 + $imagick->clear(); 132 + $imagick->destroy(); 133 + } 134 + 135 + try { 136 + $ghRequests = 0; 137 + $issueCount = githubRequest($githubToken, $ghRequests, "https://api.github.com/repos/red-prig/fpps4-game-compatibility")['open_issues_count']; 138 + $pageCount = ceil($issueCount / 100); 139 + echo "Total Issues: " . $issueCount . "<br>"; 140 + echo "Total Pages: " . $pageCount . "<br><br>"; 141 + $issuesProcessed = 0; 142 + $noImage = 0; 143 + 144 + for ($page = 1; $page <= $pageCount; $page++) { 145 + $issues = githubRequest($githubToken, $ghRequests, "https://api.github.com/repos/red-prig/fpps4-game-compatibility/issues?page=$page&per_page=100&state=open&direction=ASC"); 146 + 147 + foreach ($issues as $issue) { 148 + $id = filter_var($issue['number'], FILTER_VALIDATE_INT); 149 + $title = htmlspecialchars($issue['title']); 150 + $tags = htmlspecialchars(implode(', ', array_column($issue['labels'], 'name'))); 151 + $createdDate = htmlspecialchars(date('d/m/Y', strtotime($issue['created_at']))); 152 + $updatedDate = htmlspecialchars(date('d/m/Y', strtotime($issue['updated_at']))); 153 + $code = ""; 154 + $type = ""; 155 + 156 + // skip invalid issues 157 + if (str_contains($tags,"question") || str_contains($tags,"invalid")) { 158 + continue; 159 + } 160 + 161 + // look for an code in the title, for example: CUSA12345 or NPXS00000 and do some processing 162 + preg_match('/[a-zA-Z]{4}[0-9]{5}/', $title, $matches); 163 + if ($matches) { 164 + str_starts_with($matches[0], "CUSA") ? ($code = $matches[0]) && ($type = "CUSA") : ""; 165 + str_contains($tags, "app-homebrew") ? ($code = $matches[0]) && ($type = "HB") : ""; 166 + str_contains($tags, "app-system-fw505") ? ($code = $matches[0]) && ($type = "SYS") : ""; 167 + str_contains($tags, "app-ps2game") ? ($code = "PS2 GAME") : ""; 168 + $title = str_replace(["- " . $matches[0], "-" . $matches[0], $matches[0]], "", $title); 169 + } else { 170 + str_contains($tags, "app-homebrew") ? ($code = "HOMEBREW") && ($type = "HB") : ""; 171 + } 172 + 173 + $title = str_ireplace(["(Homebrew)", "- HOMEBREW", "Homebrew", "[]"], "", $title); 174 + $title = rtrim($title, " -"); 175 + 176 + // if (empty($code)) { 177 + // echo "skipping: $title <br>"; 178 + // continue; 179 + // } 180 + $issuesProcessed++; 181 + 182 + // Now put it into a database :3 183 + try { 184 + 185 + // tag bullshit AHHHHH 186 + if ($tags) { 187 + $tags = str_ireplace(["status-", "app-homebrew", "app-system-fw505", "app-ps2game"], '', $tags); 188 + 189 + $priority = [ 190 + 'playable', 191 + 'ingame', 192 + 'menus', 193 + 'boots', 194 + 'nothing' 195 + ]; 196 + 197 + $tagArray = array_map('trim', explode(', ', $tags)); 198 + 199 + // headache, prioritizes tags 200 + usort($tagArray, function ($a, $b) use ($priority) { 201 + $priorityA = array_search($a, $priority); 202 + $priorityB = array_search($b, $priority); 203 + 204 + $priorityA = ($priorityA === false) ? 0 : $priorityA; 205 + $priorityB = ($priorityB === false) ? 0 : $priorityB; 206 + 207 + return $priorityB <=> $priorityA; 208 + }); 209 + 210 + // Take the best tag and capitalize it 211 + // $highestPriority = ucfirst($tagArray[0]); 212 + $tagArray = array_slice($tagArray, 0, 1); 213 + 214 + // // Remove tags that are in the priority array 215 + // $tagArray = array_filter($tagArray, function ($tag) use ($priority) { 216 + // return !in_array($tag, $priority); 217 + // }); 218 + 219 + // // Add the best tag to the beginning of the array 220 + // array_unshift($tagArray, $highestPriority); 221 + 222 + $tags = ucfirst(implode(', ', $tagArray)); 223 + 224 + } else {$tags = "N/A";} 225 + 226 + 227 + $insertQuery = "INSERT INTO newIssues (id, code, title, tags, type, updatedDate, createdDate) VALUES (?, ?, ?, ?, ?, ?, ?)"; 228 + $stmt = $conn->prepare($insertQuery); 229 + 230 + $stmt->execute([$id, $code, $title, $tags, $type, $updatedDate, $createdDate]); 231 + } catch (Exception $e) { 232 + echo("Error inserting issue: $e"); 233 + } 234 + 235 + 236 + // Now download images :3 237 + try { 238 + $cusaDir = "$dir/public_html/_images/CUSA/$code.avif"; 239 + $hbDir = "$dir/public_html/_images/HB/$title.avif"; 240 + 241 + if ($type === "CUSA" && !file_exists($cusaDir)) { 242 + $stmt = $conn->prepare('SELECT * FROM GameSkips WHERE code = :code COLLATE utf8mb4_general_ci'); // check if it needs to be skipped 243 + $stmt->execute(['code' => $code]); 244 + $result = $stmt->fetch(PDO::FETCH_ASSOC); 245 + 246 + if(!$result) 247 + { 248 + $key = hex2bin($tmdbHash); 249 + $hash = strtoupper(hash_hmac("sha1", "{$code}_00", $key)); 250 + $url = "https://tmdb.np.dl.playstation.net/tmdb2/{$code}_00_{$hash}/{$code}_00.json"; 251 + $userAgent = "Mozilla/5.0 (PlayStation; PlayStation 4/11.00) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"; 252 + $PS4header = stream_context_create(["http" => ["header" => "User-Agent: $userAgent\r\n"]]); // ps4 useragent cuz im silly 253 + $response = file_get_contents($url, false, $PS4header); 254 + $data = json_decode($response, true); 255 + $url = $data['icons'][0]['icon']; 256 + 257 + usleep(rand(200000, 500000)); // delay between 200 - 500 ms 258 + imageDownloader($url, $PS4header, $cusaDir); 259 + } 260 + } else if ($type === "HB" && !file_exists($hbDir)) { 261 + $stmt = $conn->prepare('SELECT * FROM GameSkips WHERE code = :title COLLATE utf8mb4_general_ci'); // check if it needs to be skipped 262 + $stmt->execute(['title' => $title]); 263 + $result = $stmt->fetch(PDO::FETCH_ASSOC); 264 + 265 + if(!$result) { 266 + $stmt = $homebrewDB->prepare('SELECT image FROM homebrews WHERE name = :title COLLATE NOCASE'); 267 + $stmt->execute(['title' => $title]); 268 + $url = $stmt->fetch()[0]; 269 + 270 + usleep(rand(200000, 500000)); // delay between 200 - 500 ms 271 + imageDownloader($url, $HBheader, $hbDir); 272 + } 273 + } 274 + } catch (Exception $e) { 275 + $noImage++; 276 + echo "No image found for: $title <br>"; 277 + 278 + // insert issue in database to be skipped. 279 + $insertQuery = "INSERT INTO GameSkips (code) VALUES (:value1)"; 280 + $stmt = $conn->prepare($insertQuery); 281 + 282 + if ($type === "CUSA") { 283 + $stmt->execute(['value1' => $code]); 284 + } else if ($type === "HB") { 285 + $stmt->execute(['value1' => $title]); 286 + } 287 + } 288 + } 289 + } 290 + } catch (Exception $e) { 291 + echo $e; 292 + } finally { 293 + print("<br>$issuesProcessed issues processed! <br>"); 294 + print("$noImage images not found! <br>"); 295 + print("Issue processing, Image downloading and Database insertion task completed! <br>"); 296 + } 297 + 298 + // Move newIssues table to normal issues table 299 + try { 300 + // Check the newIssues table 301 + $result = $conn->query("SELECT COUNT(*) FROM newIssues"); 302 + $newTotal = $result->fetchColumn(); 303 + 304 + $result2 = $conn->query("SELECT COUNT(*) FROM issues"); 305 + $oldTotal = $result2->fetchColumn(); 306 + 307 + // remove 5% from old issue cound 308 + $minNumber = $oldTotal - (0.05 * $oldTotal); 309 + 310 + if ($newTotal > $minNumber) { 311 + // empty issues table 312 + $conn->query("DELETE FROM issues"); 313 + 314 + // copy newIssues to issues table 315 + $conn->query("INSERT INTO issues (id, code, title, tags, type, updatedDate, createdDate) SELECT id, code, title, tags, type, updatedDate, createdDate FROM newIssues"); 316 + 317 + // drop newIssues table 318 + $conn->query("DROP TABLE IF EXISTS newIssues"); 319 + } else { 320 + print "<br>Something is wrong with newIssues, skipping update."; 321 + } 322 + 323 + } catch (Exception $e) { 324 + echo $e; 325 + } finally {print("Database transfer task completed! <br>");} 326 + 327 + 328 + $conn = null; 329 + $homebrewDB = null; 330 + echo "<br>" . round((microtime(true) - $startTime) * 1000, 2) . "ms"; 331 + 332 + } else { 333 + http_response_code(404); 334 + include("$dir/document_errors/404.html"); 335 + } 336 + ?>
+247 -444
public_html/compatibility/app.js
··· 1 - let imageLoading = true; 1 + // this is my attempt on rewriting this... thing 2 2 let avifSupport = false; 3 - let sTimer; 4 - let iTimer; 5 - let pTimer; 6 - let pbTimer; 7 - let pfTimer; 8 - let pmaxTimer; 9 - let pminTimer; 10 - let skeletonTimeout; 11 - let tagFilter = []; 3 + let imageLoading = true; 12 4 let oldestFilter = false; 13 5 let datesButton = false; 14 - let lightTheme = false; 6 + let tagFilter = []; 15 7 let pageNumber = 1; 16 - let inputValue = 1; 17 - let updatePageValue = false; 18 - let noImagesLocked = false; 19 - let maxValue; 20 8 21 - var urlParams = new URLSearchParams(window.location.search); 22 - var tagParam = urlParams.get('tag'); 23 - if (tagParam) { 24 - tagFilter.push(tagParam); 25 - tagElementForFilter = document.getElementById(tagParam + 'Bar'); 26 - tagParentForFilter = tagElementForFilter.parentElement; 27 - tagParentForFilter.classList.toggle('selected'); 28 - } 9 + let Timer; 10 + let totalPages; 11 + let totalTime; 12 + let totalIssues; 13 + let fancyJsonData; // :3 29 14 30 15 31 - function setCookie(name, value) { 32 - var date = new Date(); 33 - date.setMonth(date.getMonth() + 1); 34 - var expires = "; expires=" + date.toUTCString(); 35 - document.cookie = name + "=" + value + expires + "; path=/"; 16 + // Fetch html for footer and header 17 + async function fetchHtml(path, target){ 18 + fetch(path).then(response => response.text()).then(data => { 19 + document.querySelector(target).innerHTML = data; 20 + }).catch(console.error); 36 21 } 37 22 38 - // Checks cookies 39 - function checkCookies(name, defaultValue) { 40 - return document.cookie.split("; ").find(c => c.startsWith(name + "="))?.split("=")[1] ?? defaultValue; // if cookie doesnt exist use the default value 41 - } 42 - 43 - const imageLoadingCookie = checkCookies("imageLoading", "true"); 44 - if (imageLoadingCookie === "false") { 45 - imageLoading = false; 46 - document.getElementById("imageButton").classList.add('selected'); 47 - } 48 - 49 - const dateCookie = checkCookies("datesButton", "false"); 50 - if (dateCookie === "true") { 51 - datesButton = true; 52 - 53 - document.getElementById("datesButton").classList.add('selected'); 54 - } 55 - 56 - const lightThemeCookie = checkCookies("lightTheme", "false"); 57 - if (lightThemeCookie === "true") { 58 - lightTheme = true; 59 - document.body.classList.toggle("lightMode"); 60 - } 61 - //- Checks cookies 62 - 63 - function LightModeIconChange() { 64 - if (lightTheme === true) { 65 - document.getElementById("lightModeIcon").style.display = "flex"; 66 - document.getElementById("darkModeIcon").style.display = "none"; 67 - } else { 68 - document.getElementById("darkModeIcon").style.opacity = "1"; 69 - } 70 - } 71 - 72 - function adjustFontSize() { 73 - var screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 74 - var referenceWidth = 2000; 75 - var referenceFontSize = 16; 76 - var phoneReferenceWidth = 550; 77 - 78 - if (screenWidth >= referenceWidth) { 79 - // if its larger then 2000px 80 - var fontSize = (screenWidth / referenceWidth) * referenceFontSize; 81 - document.documentElement.style.fontSize = fontSize + 'px'; 82 - } else if (screenWidth >= phoneReferenceWidth) { 83 - // if its higer then 550 but under 2000 then set it as default 84 - document.documentElement.style.fontSize = referenceFontSize + 'px'; 85 - } else { 86 - // if the width is lower then 550 87 - var fontSize = (screenWidth / phoneReferenceWidth) * referenceFontSize; 88 - document.documentElement.style.fontSize = fontSize + 'px'; 89 - } 90 - } 91 - 92 - // resize on load and when rezsizing the window 93 - window.addEventListener('load', adjustFontSize); 94 - window.addEventListener('resize', adjustFontSize); 95 23 96 24 // Check Avif Support 97 25 console.log(`Hey there! I've implemented an avif support check to spare browsers like Edge from having a stroke :D!`); ··· 104 32 avif.onerror = function() { 105 33 console.log('AVIF IS NOT SUPPORTED D:'); 106 34 avifSupport = false; 107 - noImagesLocked = true; 108 - window.alert("Hey! Your browser doesnt support avif, avif is an image format that has low file sizes while having high quality images. I will give you an N/A jpeg instead."); 109 - imageButton(); 35 + // window.alert("Hey! Your browser doesnt support avif, avif is an image format that has low file sizes while having high quality images. You won't get any game images"); 36 + const iButton = document.getElementById('imageButton'); 37 + console.log(iButton); 38 + iButton.classList.add('selected'); 39 + iButton.style.cursor = 'default'; 40 + iButton.removeAttribute("onclick"); 110 41 }; 111 42 112 - // Page Load 43 + 44 + 45 + // game cards and stats handler and other onload stuff 113 46 document.addEventListener('DOMContentLoaded', function() { 114 - fetch('https://fpps4.net/scripts/search.php?q=&stats&tag='+ tagFilter) 115 - .then(response => response.text()) 116 - .then(data => { 117 - document.querySelector('#gameWrapper').innerHTML = data; 118 - applyMods(); 119 - gameStats(); 120 - filter(); 47 + // + check cookies 48 + const imageLoadingCookie = checkCookies("imageLoadingSetting", "true"); 49 + const datesSetting = checkCookies("datesSetting", "false"); 50 + 51 + if (imageLoadingCookie === "false") { 52 + imageLoading = false; 53 + document.getElementById("imageButton").classList.add('selected'); 54 + } 55 + 56 + if (datesSetting === "true") { 57 + datesButton = true; 58 + document.getElementById('datesButton').classList.toggle('selected'); 59 + } 60 + 61 + // Adjust screen size for mobile and 4k monitors for some reason 62 + window.addEventListener('load', adjustScreenSize); 63 + window.addEventListener('resize', adjustScreenSize); 64 + 65 + 66 + // + fetch issues and set the tag bars 67 + fetch('/_scripts/search.php?q=&stats') 68 + .then(response => response.json()) 69 + .then(jsonData => { 70 + gameCardHandler(jsonData); 71 + fancyJsonData = jsonData; 72 + pageButtonHandler(); 73 + 74 + totalPages = jsonData.info.pages; 75 + totalTime = jsonData.info.time; 76 + totalIssues = jsonData.info.issues; 77 + console.log("\nCOMPATIBILITY STATS"); 78 + 79 + // stats & tag filter 80 + jsonData.stats.forEach(stat => { 81 + var tag = stat.tag; 82 + var percent = stat.percent; 83 + var element = document.getElementById(tag + 'Bar'); 84 + var textElement = document.getElementById(tag + 'Info') 85 + var parentElement = element.parentElement; 86 + console.log(`${tag} = ${percent}% [${stat.count}]`); 87 + element.style.width = percent + '%'; 88 + textElement.textContent = percent + '% - ' + stat.count; 89 + 90 + parentElement.addEventListener('click', function() { 91 + parentElement.classList.toggle('selected'); 92 + tagFilter.includes(tag) ? tagFilter.splice(tagFilter.indexOf(tag), 1) : tagFilter.push(tag); 93 + pageNumber = 1; 94 + updateSearchResults(); 95 + }); 96 + }); 97 + console.log("\n"); 121 98 }) 122 99 .catch(console.error); 123 100 }); 124 101 125 - // Game Stats 126 - function gameStats() { 127 - var labelData = []; 128 - var tempPercentage = 0; 129 - var tempTotal = 0; 130 - var labels = ['N/A', 'Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; 131 - console.log("\nCOMPATIBILITY STATS"); 132 102 133 - labels.forEach(label => { 134 - var div = document.getElementById(label).getAttribute('data').split('+'); 135 - var percentage = div[0]; 136 - var total = div[1]; 137 - labelData[label] = [percentage, total]; 138 - console.log(label + ' = ' + percentage + '% ['+ total +']'); 139 - }); 140 - console.log("\n"); 141 - 142 - for (var label in labelData) { 143 - var data = labelData[label]; 144 - var percentage = data[0]; 145 - var total = data[1]; 146 - if (label === 'N/A' || label === 'Nothing') { //combine N/A & Nothing 147 - tempPercentage = (parseFloat(percentage) + parseFloat(tempPercentage)); 148 - tempTotal = (parseFloat(total) + parseFloat(tempTotal)); 149 - percentage = tempPercentage.toFixed(2); 150 - total = tempTotal.toFixed(0); 151 - element = document.getElementById('NothingBar'); 152 - text = document.getElementById('NothingInfo') 153 - } else { 154 - element = document.getElementById(label + 'Bar'); 155 - text = document.getElementById(label + 'Info') 156 - } 157 - element.style.width = percentage + '%'; 158 - text.textContent = percentage + '% - ' + total; 159 - } 160 - }; 103 + // Header & Footer Load 104 + fetchHtml("/_parts/navbar.html", "#header"); 105 + fetchHtml("/_parts/footer.html", "#footer"); 161 106 162 - // Header Load 163 - fetch('https://fpps4.net/parts/navbar.html') 164 - .then(response => response.text()) 165 - .then(data => { 166 - document.querySelector('#header').innerHTML = data; 167 - LightModeIconChange(); 168 - }) 169 - .catch(console.error); 170 107 171 108 // Searching 172 109 document.querySelector('#search').addEventListener('input', function() { 173 - updatePageValue = true; 174 110 pageNumber = 1; 175 - UpdateSearchResults() 111 + updateSearchResults(); 176 112 }); 177 113 178 - function UpdateSearchResults() { 179 - clearTimeout(sTimer); 114 + async function updateSearchResults() { 115 + clearTimeout(Timer); 116 + const gameWrapper = document.querySelector('#gameWrapper'); 117 + const searchQuery = document.querySelector('#search').value; 118 + pageButtonHandler(); 180 119 181 - const gameWrapper = document.querySelector('#gameWrapper'); 182 120 gameWrapper.querySelectorAll('.gameContainer').forEach(container => { 183 121 const skeletonDiv = document.createElement('div'); 184 122 skeletonDiv.classList.add('gameContainer', 'skeletonAnimation'); 185 123 gameWrapper.replaceChild(skeletonDiv, container); 186 124 }); 187 125 188 - sTimer = setTimeout(() => { 189 - const searchQuery = document.querySelector('#search').value; 190 - fetch('https://fpps4.net/scripts/search.php?q=' + searchQuery + '&tag=' + tagFilter + '&page=' + pageNumber + '&oldest=' + oldestFilter) 191 - .then(response => response.text()) 192 - .then(data => { 193 - document.querySelector('#gameWrapper').innerHTML = data; 194 - applyMods(); 195 - }) 196 - .catch(console.error); 126 + Timer = setTimeout(() => { 127 + fetch('/_scripts/search.php?q=' + searchQuery + '&tag=' + tagFilter + '&page=' + pageNumber + '&oldest=' + oldestFilter) 128 + .then(response => response.json()) 129 + .then(jsonData => { 130 + fancyJsonData = jsonData; 131 + gameCardHandler(jsonData); 132 + }) 133 + .catch(console.error); 197 134 }, 300); 198 135 } 199 136 200 - // Filters 201 - function filter() { 202 - var ids = ['Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; 203 - ids.forEach(id => { 204 - element = document.getElementById(id + 'Bar'); 205 - parent = element.parentElement; 206 - parent.addEventListener('click', function() { 207 - this.classList.toggle('selected'); 208 - 209 - tagFilter.includes(id) ? tagFilter.splice(tagFilter.indexOf(id), 1) : tagFilter.push(id); 210 - console.log('Tag Filter has been updated to: ' + tagFilter); 211 - updatePageValue = true; 212 - pageNumber = 1; 213 - UpdateSearchResults(); 214 - }); 215 - }); 216 - }; 137 + // Game Card handler 138 + async function gameCardHandler(jsonData) { 139 + const gameWrapper = document.getElementById("gameWrapper"); 140 + gameWrapper.innerHTML = ""; 141 + 142 + jsonData.games.forEach(game => { 143 + // game image URL 144 + let imageSource = ""; 145 + let imageText = "N/A"; 146 + let imageTextSize = 1.38; 147 + 148 + switch(true) { 149 + case game.image && imageLoading && avifSupport && game.type === "HB": 150 + imageSource = "/_images/HB/" + game.title + ".avif"; 151 + break; 152 + case game.image && imageLoading && avifSupport: 153 + imageSource = "/_images/CUSA/" + game.code +".avif"; 154 + break; 155 + case game.type === "SYS": 156 + imageText = "SYSTEM"; 157 + imageTextSize = 1.13; 158 + break 159 + } 217 160 218 - // Image Handler 219 - function imageHandler() { 220 - document.querySelectorAll('.gameImage').forEach(gameImage => { 221 - gameImage.setAttribute("loading", "lazy"); 222 - const data = gameImage.dataset.cusa; 223 - gameImage.src = data.includes('CUSA') && imageLoading ? (avifSupport ? "https://fpps4.net/images/CUSA/" + data + ".avif" : "https://fpps4.net/images/NA.jpg") : (avifSupport ? "https://fpps4.net/images/NA.avif" : "https://fpps4.net/images/NA.jpg"); 224 - }); 225 - } 161 + if (game.type === "HB") { // needs to be applied to all homebrews 162 + imageText = "HOME<br>BREW"; 163 + imageTextSize = 1.25; 164 + } 226 165 227 - // Link Handler 228 - function linkHandler() { 229 - document.querySelectorAll('.gameImageLink').forEach(link => { 230 - link.setAttribute("target", "_blank"); 231 - link.href = "https://github.com/red-prig/fpps4-game-compatibility/issues/" + link.dataset.id; 232 - link.removeAttribute('data-id'); 233 - }); 234 - } 166 + let imageTextEnabled = game.image && imageLoading && avifSupport ? "none" : "flex"; 235 167 236 - // Game Status Colors 237 - function gameColors() { 238 - document.querySelectorAll('.gameContainer').forEach(game => { 239 - const status = game.querySelector('.gameStatus').textContent; 240 - const statusClass = (['Nothing', 'Boots', 'Ingame', 'Menus', 'Playable'].includes(status) ? status : 'Nothing'); 241 - game.querySelector('.gameStatus').classList.add(statusClass); 242 - game.querySelector('.gameSeparator').classList.add(statusClass); 168 + // game cards 169 + const gameElementHTML = ` 170 + <div class="gameContainer"> 171 + <a class="gameImageLink" target="_blank" href="https://github.com/red-prig/fpps4-game-compatibility/issues/${game.id}"> 172 + <p class="gameImageText" style="font-size: ${imageTextSize}rem; display: ${imageTextEnabled};">${imageText}</p> 173 + ${imageSource ? `<img class="gameImage" loading="lazy" alt="${game.title} - ${game.code} game image" src="${imageSource}">` : "" } 174 + </a> 175 + <div class="gameSeparator ${game.tag}"></div> 176 + <div class="gameDetails"> 177 + <p class="gameName">${game.title}</p> 178 + <p class="gameCusa" data-date="${game.upDate}" data-cusa="${game.code}">${game.code}</p> 179 + <p class="gameStatus ${game.tag}">${game.tag}</p> 180 + </div> 181 + </div>`; 182 + 183 + const tempContainer = document.createElement('div'); 184 + tempContainer.innerHTML = gameElementHTML; 185 + const gameContainer = tempContainer.querySelector('.gameContainer'); 186 + gameWrapper.appendChild(gameContainer); 243 187 }); 244 - } 188 + 189 + const statContainer = document.createElement('h4'); 190 + const stat = `<h4 class="totalTimeText">${jsonData.info.issues} results in ${jsonData.info.time}ms </h4>`; 191 + statContainer.innerHTML = stat; 192 + gameWrapper.appendChild(statContainer); 193 + if (datesButton) { 194 + dateButtonHandler(); 195 + } 245 196 246 - // Image Effect 247 - function imageEffect() { 248 - document.querySelectorAll('.gameImage').forEach(image => { 197 + // Image Effect 198 + document.querySelectorAll('.gameImage, .gameImageText').forEach(image => { 249 199 image.addEventListener('mousemove', e => { 250 200 const r = image.getBoundingClientRect(); 251 201 const x = e.clientX - r.left; ··· 257 207 image.style.transform = 'scale(1)'; 258 208 }); 259 209 }); 210 + // functions in required.js 211 + updateFooter(); 212 + LightModeIconChange(); 260 213 } 261 214 262 - function applyMods() { 263 - gameColors(); 264 - imageHandler(); 265 - linkHandler(); 266 - imageEffect(); 267 - dateHandler(); 268 - updatePageSelector(); 269 - updateFooter() 270 - } 271 - 272 - // update footer position 273 - function updateFooter() { 274 - const viewportHeight = window.innerHeight; 275 - const bodyHeight = document.body.clientHeight; 276 - if (bodyHeight < viewportHeight) { 277 - document.getElementById('footer').style.position = 'fixed'; 278 - } else { 279 - document.getElementById('footer').style = ''; 280 - } 281 - } 282 215 283 216 // NoImage button 284 - function imageButton() { 285 - e = document.getElementById('imageButton'); 286 - if (noImagesLocked === true) { 287 - e.classList.add('selected'); 288 - e.style.cursor = 'default'; 289 - } else { 290 - clearTimeout(iTimer); 291 - e.classList.toggle('selected'); 292 - 293 - imageLoading = !imageLoading; 294 - setCookie("imageLoading", imageLoading); 295 - iTimer = setTimeout(imageHandler, 450); 296 - } 217 + function imageButton(button) { 218 + imageLoading = !imageLoading; 219 + setCookie("imageLoadingSetting", imageLoading); 220 + button.classList.toggle('selected'); 221 + imageButtonHandler(); 297 222 } 298 223 299 - // show last updated dates button 300 - function dateButton() { 224 + 225 + // Date Button 226 + function dateButton(button) { 301 227 datesButton = !datesButton; 302 - setCookie("datesButton", datesButton); 303 - dateHandler(); 228 + setCookie("datesSetting", datesButton); 229 + button.classList.toggle('selected'); 230 + dateButtonHandler(); 304 231 } 305 232 306 - function dateHandler() { 307 - var gameCusaText = document.querySelectorAll(".gameCusa"); 308 - var button = document.getElementById('datesButton'); 309 - datesButton ? button.classList.add('selected') : button.classList.remove('selected'); 310 233 311 - gameCusaText.forEach(element => { 312 - var currentText = element.textContent; 313 - var date = element.getAttribute('data'); 314 - 315 - if (datesButton === true) { 316 - element.dataset.status = currentText; 317 - element.textContent = date; 318 - } else if (currentText === date) { 319 - element.textContent = element.dataset.status; 320 - } 321 - }); 322 - } 323 - 324 - // Sorting Button 325 - function sortButton(e) { 326 - clearTimeout(iTimer); 234 + // Oldes/Newest Button 235 + function sortButton(button) { 327 236 oldestFilter = !oldestFilter; 328 - e.classList.toggle('selected'); 329 - iTimer = setTimeout(UpdateSearchResults, 450); 237 + button.classList.toggle('selected'); 238 + updateSearchResults(); 330 239 } 331 240 332 - function toggleLightMode() { 333 - lightTheme = !lightTheme; 334 - setCookie("lightTheme", lightTheme); 335 - document.body.classList.toggle("lightMode"); 336 - var x = document.getElementById("darkModeIcon") 337 - var y = document.getElementById("lightModeIcon") 338 - if (y.style.display === "none" || y.style.display == '') { 339 - y.style.display = "flex"; 340 - x.style.display = "none"; 341 - } else { 342 - x.style.opacity = "1"; 343 - x.style.display = "flex"; 344 - y.style.display = "none"; 345 - }; 346 - }; 347 - 348 - function toggleMenu() { 349 - // var x = document.getElementById("overlay"); 350 - var y = document.getElementById("close-icon") 351 - var z = document.getElementById("menu-icon") 352 - console.log('pretend like you see a menu') 353 - if (y.style.display === "none" || y.style.display == '') { 354 - // x.style.display = "flex"; 355 - y.style.display = "flex"; 356 - z.style.display = "none"; 357 - setTimeout(function() { 358 - // x.style.opacity = 1; 359 - }, 50); 360 - } else { 361 - // x.style.opacity = 0; 362 - y.style.display = "none"; 363 - z.style.display = "flex"; 364 - setTimeout(function() { 365 - // x.style.display = "none"; 366 - }, 300); 367 - }; 368 - }; 369 - 370 - const inputElement = document.getElementById('search2'); 371 - function updatePageSelector() { 372 - search3.classList.add('selected'); 373 - maxValue = document.getElementById("totalPages").getAttribute('data'); 374 - if (updatePageValue === true) { 375 - inputValue = 1; 376 - updatePageValue = false; 377 - document.getElementById('pageBarMin').classList.add('selected'); 378 - } 379 - 380 - if (inputValue == 1) { 381 - document.getElementById('pageBarMin').classList.add('selected'); 382 - search3.placeholder = '...'; 383 - search3.classList.remove('selected'); 384 - } else { 385 - document.getElementById('pageBarMin').classList.remove('selected'); 386 - } 387 241 388 - if (inputValue == maxValue) { 389 - document.getElementById('pageBarMax').classList.add('selected'); 390 - search3.placeholder = '...'; 391 - search3.classList.remove('selected'); 242 + async function imageButtonHandler() { 243 + if (imageLoading === false) { 244 + document.querySelectorAll(".gameImageText").forEach(imageText => { 245 + imageText.style.display = "flex"; 246 + }); 392 247 } else { 393 - document.getElementById('pageBarMax').classList.remove('selected'); 248 + gameCardHandler(fancyJsonData); 394 249 } 250 + } 395 251 396 - document.getElementById('pageBarMax').textContent = maxValue; 397 - inputElement.placeholder = inputValue + "/" + maxValue; 398 252 399 - inputElement.addEventListener('input', function(event) { 400 - clearTimeout(pTimer); 401 - inputValue = parseInt(inputElement.value, 10); 402 - 403 - if (isNaN(parseFloat(inputValue))) { 404 - inputValue = 1; 253 + async function dateButtonHandler() { 254 + document.querySelectorAll(".gameCusa").forEach(element => { 255 + if (datesButton === true) { 256 + element.textContent = element.dataset.date; 257 + } else { 258 + element.textContent = element.dataset.cusa; 405 259 } 406 - if (inputValue > maxValue) { 407 - inputValue = maxValue; 408 - } else if (inputValue < 1) { 409 - inputValue = 1; 410 - } 411 - 412 - inputElement.placeholder = inputValue + "/" + maxValue; 413 - search3.placeholder = inputValue; 414 - pTimer = setTimeout(() => { 415 - if (inputValue > 9) { 416 - inputElement.style.padding = "0 0.3rem 0 0.7rem"; 417 - } else if (inputValue < 10) { 418 - inputElement.style.padding = ""; 419 - } 420 - inputElement.value = ""; 421 - search3.value = ""; 422 - pageNumber = inputValue; 423 - UpdateSearchResults(); 424 - }, 500); 425 260 }); 426 261 } 427 262 428 - function pageBarBack() { 429 - if (pageNumber > 1) { 430 - clearTimeout(pbTimer); 431 - inputValue--; 432 - pageNumber--; 433 - document.getElementById('pageBarMax').classList.remove('selected'); 434 - if (pageNumber == 1) { 435 - search3.placeholder = '...'; 436 - search3.classList.remove('selected'); 437 - document.getElementById('pageBarMin').classList.add('selected'); 438 - } else { 439 - search3.placeholder = pageNumber; 440 - search3.classList.add('selected'); 263 + function pageButtonHandler(type) { 264 + // maybe make it handle everything in once? 265 + const maxNumber = fancyJsonData.info.pages; 266 + const searchBar = document.getElementById("search3"); 267 + const minButton = document.getElementById("pageBarMin"); 268 + const maxButton = document.getElementById("pageBarMax"); 269 + 270 + if (pageNumber != maxNumber) { 271 + if (type === "forward") { 272 + pageNumber += 1; 273 + updateSearchResults(); 274 + } else if (type === "max") { 275 + pageNumber = maxNumber; 276 + updateSearchResults(); 441 277 } 442 - pbTimer = setTimeout(() => { 443 - UpdateSearchResults(); 444 - }, 500); 445 278 } 446 - } 447 279 448 - function pageBarForward() { 449 - maxValue = document.getElementById("totalPages").getAttribute('data'); 450 - if (inputValue < maxValue) { 451 - clearTimeout(pfTimer); 452 - inputValue++; 453 - pageNumber++; 454 - document.getElementById('pageBarMin').classList.remove('selected'); 455 - if (pageNumber == maxValue) { 456 - search3.placeholder = '...'; 457 - search3.classList.remove('selected'); 458 - document.getElementById('pageBarMax').classList.add('selected'); 459 - } else { 460 - search3.placeholder = inputValue; 461 - search3.classList.add('selected'); 280 + if (pageNumber != 1) { 281 + if (type === "back") { 282 + pageNumber -= 1; 283 + updateSearchResults(); 284 + } else if (type === "min") { 285 + pageNumber = 1; 286 + updateSearchResults(); 462 287 } 463 - pfTimer = setTimeout(() => { 464 - UpdateSearchResults(); 465 - }, 500); 466 288 } 467 - } 468 289 469 - function pageBarMax() { 470 - clearTimeout(pmaxTimer); 471 - document.getElementById('pageBarMax').classList.add('selected'); 472 - document.getElementById('pageBarMin').classList.remove('selected'); 473 - inputValue = maxValue; 474 - search3.placeholder = '...'; 475 - search3.classList.remove('selected'); 476 - pageNumber = maxValue; 477 - pmaxTimer = setTimeout(() => { 478 - UpdateSearchResults(); 479 - }, 400); 480 - } 290 + if (type === "input") { 291 + clearTimeout(Timer); 292 + inputValue = parseInt(search3.value, 10); 293 + Timer = setTimeout(() => { 294 + 295 + console.log(inputValue); 296 + pageNumber = inputValue; 297 + updateSearchResults(); 298 + searchBar.value = ""; 299 + // if (inputValue > maxNumber) { 300 + // pageNumber = inputValue; 301 + // updateSearchResults(); 302 + // searchBar.value = ""; 303 + // } else { 304 + // pageNumber = maxNumber; 305 + // updateSearchResults(); 306 + // searchBar.value = ""; 307 + // } 308 + }, 600); 309 + } 481 310 482 - function pageBarMin() { 483 - clearTimeout(pminTimer); 484 - document.getElementById('pageBarMin').classList.add('selected'); 485 - document.getElementById('pageBarMax').classList.remove('selected'); 486 - search3.placeholder = '...'; 487 - search3.classList.remove('selected'); 488 - inputValue = 1; 489 - pageNumber = 1; 490 - pminTimer = setTimeout(() => { 491 - UpdateSearchResults(); 492 - search3.placeholder = '...'; 493 - }, 400); 311 + maxButton.textContent = maxNumber; 312 + // searchBar.value = ""; 313 + 314 + if (pageNumber != 1 && pageNumber != maxNumber) { 315 + searchBar.placeholder = pageNumber; 316 + searchBar.classList.add("selected"); 317 + maxButton.classList.remove("selected"); 318 + minButton.classList.remove("selected"); 319 + } else if (pageNumber === 1) { 320 + minButton.classList.add("selected"); 321 + maxButton.classList.remove("selected"); 322 + searchBar.classList.remove("selected"); 323 + searchBar.placeholder = "..."; 324 + searchBar.value = ""; 325 + } else if (pageNumber === maxNumber) { 326 + minButton.classList.remove("selected"); 327 + maxButton.classList.add("selected"); 328 + searchBar.classList.remove("selected"); 329 + searchBar.placeholder = "..."; 330 + searchBar.value = ""; 331 + } 494 332 } 495 333 496 - const search3 = document.getElementById("search3"); 497 - 498 - search3.addEventListener("click", function() { 334 + search3.addEventListener("click", async function() { 499 335 if (search3.placeholder == '...') { 500 336 search3.placeholder = ''; 501 337 } 502 338 }); 503 339 504 - search3.addEventListener("blur", function() { 340 + search3.addEventListener("blur", async function() { 505 341 if (search3.placeholder == '') { 506 342 search3.placeholder = '...'; 507 343 } 508 344 }); 509 345 510 - search3.addEventListener('input', function(event) { 511 - clearTimeout(pTimer); 512 - inputValue = parseInt(search3.value, 10); 513 - document.getElementById('pageBarMax').classList.remove('selected'); 514 - document.getElementById('pageBarMin').classList.remove('selected'); 515 - 516 - if (isNaN(parseFloat(inputValue))) { 517 - inputValue = 1; 518 - } 519 - if (inputValue > maxValue) { 520 - inputValue = maxValue; 521 - } else if (inputValue < 1) { 522 - inputValue = 1; 523 - } 524 - 525 - inputElement.placeholder = inputValue + "/" + maxValue; 526 - search3.placeholder = inputValue; 527 - pTimer = setTimeout(() => { 528 - if (inputValue > 9) { 529 - inputElement.style.padding = "0 0.3rem 0 0.7rem"; 530 - } else if (inputValue < 10) { 531 - inputElement.style.padding = ""; 532 - } 533 - inputElement.value = ""; 534 - search3.value = ""; 535 - search3.classList.add('selected'); 536 - pageNumber = inputValue; 537 - UpdateSearchResults(); 538 - }, 500); 539 - }); 540 - 541 - // Footer Load 542 - fetch('https://fpps4.net/parts/footer.html') 543 - .then(response => response.text()) 544 - .then(data => { 545 - document.querySelector('#footer').innerHTML = data; 546 - }) 547 - .catch(console.error); 346 + // search3.addEventListener('input', async function() { 347 + // clearTimeout(Timer); 348 + // inputValue = parseInt(search3.value, 10); 349 + // console.log(inputValue); 350 + // });
+11 -11
public_html/compatibility/index.html
··· 3 3 <head> 4 4 <meta charset="UTF-8"> 5 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 - <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 7 <title>fpPS4 - Compatibility List</title> 8 8 <meta property="title" content="Game Compatibility List"> 9 9 <meta property="og:title" content="fpPS4 - Game Compatibility List"> ··· 17 17 <meta name="robots" content="index,follow"> 18 18 <meta name="author" content="Mr. Snowy"> 19 19 <link rel="stylesheet" href="./styles.css"> 20 - <link rel="icon" href="https://fpps4.net/images/fpPS4Logo.png" type="image/png"> 20 + <link rel="icon" href="/_images/fpPS4Logo.png" type="image/png"> 21 21 </head> 22 22 <style> 23 23 /* fixes page load stuff */ ··· 48 48 <div class="searchContainer"> 49 49 <div class="searchBarContainer"> 50 50 <input autocomplete="off" type="text" name="fpps4" class="searchBar" id="search" placeholder="Search TITLE / CUSA"> 51 - <input autocomplete="off" type="number" min="1" placeholder="1/1" name="fpps4" class="pageSelector" id="search2"> 52 51 </div> 53 52 54 53 <div class="optionButtons"> 55 54 <div onclick="sortButton(this)" class="optionButton">Oldest</div> 56 - <div id="imageButton" onclick="imageButton()" class="optionButton">No Images</div> 57 - <div id="datesButton" onclick="dateButton()" class="optionButton">Dates</div> 55 + <div id="imageButton" onclick="imageButton(this)" class="optionButton">No Images</div> 56 + <div id="datesButton" onclick="dateButton(this)" class="optionButton">Dates</div> 58 57 </div> 59 58 </div> 60 59 <div id="gameWrapper" class="gameWrapper"> ··· 81 80 <h4 class="totalTimeText">0 results in 0ms </h4> 82 81 </div> 83 82 <div class="pageBarContainer"> 84 - <img class="pageBarImage" id="pageBarBack" onclick="pageBarBack()" src="../images/arrow_back.svg" alt=""> 85 - <p class="pageBarButton" id="pageBarMin" onclick="pageBarMin()">1</p> 86 - <input class="pageBarSearch" id="search3" autocomplete="off" type="number" min="1" placeholder="..." name="fpps4"> 87 - <p class="pageBarButton" id="pageBarMax" onclick="pageBarMax()">1</p> 88 - <img class="pageBarImage" id="pageBarForward" onclick="pageBarForward()" src="../images/arrow_forward.svg" alt=""> 83 + <img class="pageBarImage" id="pageBarBack" onclick="pageButtonHandler('back')" src="/_images/arrow.svg" alt=""> 84 + <p class="pageBarButton" id="pageBarMin" onclick="pageButtonHandler('min')">1</p> 85 + <input class="pageBarSearch" id="search3" autocomplete="off" type="number" min="1" placeholder="..." name="fpps4" oninput="pageButtonHandler('input')"> 86 + <p class="pageBarButton" id="pageBarMax" onclick="pageButtonHandler('max')">1</p> 87 + <img class="pageBarImage" id="pageBarForward" onclick="pageButtonHandler('forward')" src="/_images/arrow.svg" alt="" style="rotate: 180deg;"> 89 88 </div> 90 89 <h5 style="text-align: center; font-size: 0.8rem;">Trademarks and logos displayed on this website are the property of their respective owners.<br> The use of any third-party trademarks, brand names, product names, and logos is for<br> informational purposes only and does not imply endorsement or sponsorship.</h5> 91 90 <br> ··· 98 97 } 99 98 </style> 100 99 </footer> 101 - <script defer src="app.js"></script> 100 + <script defer src="/_parts/required.js"></script> 101 + <script defer src="./app.js"></script> 102 102 </body> 103 103 </html>
+19 -17
public_html/compatibility/styles.css
··· 41 41 background-color: yellow; 42 42 } */ 43 43 44 - .Nothing {--status-color: #1F2325;} 44 + .Nothing, .N\/A {--status-color: #1F2325;} 45 45 .Boots {--status-color: #F2766E;} 46 46 .Menus {--status-color: #4288B7;} 47 47 .Ingame {--status-color: #fabb44;} ··· 163 163 font-size: 0.9rem; 164 164 transition: opacity 0.15s ease-in-out; 165 165 } 166 + .selected .progressBarInfo{opacity: 1;} 166 167 .selected, .selected:hover {background: var(--selected) !important;} 167 168 /*- PROGRESS BAR*/ 168 169 169 170 170 171 .searchBarContainer {display: flex;} 171 - .searchBar, 172 - .pageSelector { 172 + .searchBar { 173 173 padding-left: 1rem; 174 - /* width: 19.4rem; */ 174 + width: 18.4rem; 175 175 height: 2.15rem; 176 176 margin: 1.9rem 0 0.3rem; 177 177 background: var(--main1); 178 178 border: 0.05rem solid var(--border); 179 - /* border-radius: 0.6rem; */ 179 + border-radius: 0.6rem; 180 180 line-height: 0; 181 181 font-size: 0.9rem; 182 182 } 183 183 184 - .searchBar { 185 - width: 14.3rem; 186 - border-radius: 0.6rem 0rem 0rem 0.6rem; 187 - } 188 - 189 - .pageSelector { 190 - width: 3rem; 191 - border-radius: 0rem 0.6rem 0.6rem 0rem; 192 - font-weight: 500; 193 - } 194 184 195 185 input[type="number"] { 196 186 -moz-appearance: textfield; ··· 277 267 border-radius: 0.6rem 0.4rem 0.4rem 0.6rem; 278 268 overflow: hidden; 279 269 } 280 - 270 + .gameImageText, 281 271 .gameImage { 282 272 width: 5.3rem; 283 273 height: 5.3rem; 284 274 max-width: 5.3rem; 285 275 border-radius: 0.5rem 0.4rem 0.4rem 0.5rem; 286 276 transition: transform 0.2s ease-in-out; 277 + image-rendering: -webkit-optimize-contrast; 278 + } 279 + 280 + .gameImageText { 281 + background: #1F2325; 282 + font-weight: 500; 283 + /* display: flex; */ 284 + align-content: center; 285 + text-align: center; 286 + flex-wrap: wrap; 287 + justify-content: center; 288 + color: white; 289 + user-select: none; 287 290 } 288 291 289 292 .gameSeparator { ··· 409 412 @media screen and (max-width: 550px) { 410 413 .optionButton:hover {background: var(--main1);} 411 414 .progressWrap:hover, .progressWrapb:hover {background: var(--main1);} 412 - .selected .progressBarInfo{opacity: 1;} 413 415 .menu-icon:hover, .gh-logo:hover, .dc-logo:hover, .lightModeButton:hover, .logo:hover {background-color: #00000000 !important;} 414 416 .pageBarImage:hover {background-color: transparent !important;} 415 417 .gameDetails:hover .gameName {width: 23rem !important;}
public_html/images/NA.avif

This is a binary file and will not be displayed.

public_html/images/NA.jpg

This is a binary file and will not be displayed.

public_html/images/NA.png

This is a binary file and will not be displayed.

public_html/images/arrow_back.svg public_html/_images/arrow.svg
-1
public_html/images/arrow_forward.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="m304-82-56-57 343-343-343-343 56-57 400 400L304-82Z"/></svg>
public_html/images/fpPS4-icon.png

This is a binary file and will not be displayed.

public_html/images/fpPS4Logo.png public_html/_images/fpPS4Logo.png
public_html/images/fpPS4Logo1080.png public_html/_images/fpPS4Logo1080.png
public_html/images/fpPS4Logo512.png public_html/_images/fpPS4Logo512.png
+65 -100
public_html/index.html
··· 1 + <!-- 2 + _ __ __ __ 3 + | | / /__ / /________ ____ ___ ___ / /_____ _ 4 + | | /| / / _ \/ / ___/ __ \/ __ `__ \/ _ \ / __/ __ \ (_) 5 + | |/ |/ / __/ / /__/ /_/ / / / / / / __/ / /_/ /_/ / _ 6 + |__/|__/\___/_/\___/\____/_/ /_/ /_/\___/ \__/\____/ (_) 7 + ____ ____ _____ __ __ 8 + / __/___ / __ \/ ___// // / 9 + / /_/ __ \/ /_/ /\__ \/ // /_ 10 + / __/ /_/ / ____/___/ /__ __/ 11 + /_/ / .___/_/ /____/ /_/ 12 + /_/ 13 + --> 1 14 <!DOCTYPE html> 2 15 <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8"> 5 - <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 - <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> 7 - <title>fpPS4 - Compatibility List</title> 8 - <meta property="title" content="Game Compatibility List"> 9 - <meta property="og:title" content="fpPS4 - Game Compatibility List"> 10 - <meta property="og:description" content="These are the games that have been tested with fpPS4"> 11 - <meta property="og:image" content="https://fpps4.net/images/fpPS4Logo.png"> 12 - <meta property="og:url" content="https://fpps4.net/compatibility"> 13 - <meta name="description" content="These are the games that have been tested with fpPS4"> 14 - <meta name="theme-color" content="#4C566A"> 15 - <meta name="copyright" content="fpPS4"> 16 - <meta name="keywords" content="fpPS4, playstation, ps4, playstation 4, emulator, windows, open source, free pascal, compatibility layer, red-prig, compatibility list, compatibility, fpps4 compatibility list, fpps4 compatibility, fpps4 game compatibility"> 17 - <meta name="robots" content="index,follow"> 18 - <meta name="author" content="Mr. Snowy"> 19 - <link rel="stylesheet" href="./styles.css"> 20 - <link rel="icon" href="https://fpps4.net/images/fpPS4Logo.png" type="image/png"> 21 - </head> 22 - <style> 23 - /* fixes page load stuff */ 24 - .progressBarInfo {opacity: 0;} 25 - </style> 26 - <body> 27 - <header id="header"> 28 - <style> 29 - header { 30 - position: fixed; 31 - height: 3rem; 32 - } 33 - </style> 34 - </header> 35 - <main class="main"> 36 - <h1 class="mainText">Game Compatibility List</h1> 37 - <h3 class="smolMainText">These are the games that have been tested with <span style="color: #f0e74a;">fp</span>PS4.<br>Click on an image to view the game's GitHub issue.<br>The database is updated every 20 minutes.</h3> 38 - <div class=progressContainer> 39 - <div class="progressWrap"><span class="progressBarInfo" id="PlayableInfo"></span><span class="progressBarText">Playable</span><div class="progressBar" id="PlayableBar" style="background:#54A396;"></div></div> 40 - <div class="progressRow"> 41 - <div class="progressWrap"><span class="progressBarInfo" id="MenusInfo"></span><span class="progressBarText">Menus</span><div class="progressBar" id="MenusBar" style="background:#4288B7;"></div></div> 42 - <div class="progressWrap"><span class="progressBarInfo" id="IngameInfo"></span><span class="progressBarText">Ingame</span><div class="progressBar" id="IngameBar" style="background:#fabb44;"></div></div> 43 - </div> 44 - <div class="progressRow"> 45 - <div class="progressWrap"><span class="progressBarInfo" id="NothingInfo"></span><span class="progressBarText">Nothing</span><div class="progressBar" id="NothingBar" style="background:#1F2325;"></div></div> 46 - <div class="progressWrap"><span class="progressBarInfo" id="BootsInfo"></span><span class="progressBarText">Boots</span><div class="progressBar" id="BootsBar" style="background:#F2766E;"></div></div> 47 - </div></div> 48 - <div class="searchContainer"> 49 - <div class="searchBarContainer"> 50 - <input autocomplete="off" type="text" name="fpps4" class="searchBar" id="search" placeholder="Search TITLE / CUSA"> 51 - <input autocomplete="off" type="number" min="1" placeholder="1/1" name="fpps4" class="pageSelector" id="search2"> 52 - </div> 53 - 54 - <div class="optionButtons"> 55 - <div onclick="sortButton(this)" class="optionButton">Oldest</div> 56 - <div id="imageButton" onclick="imageButton()" class="optionButton">No Images</div> 57 - <div id="datesButton" onclick="dateButton()" class="optionButton">Dates</div> 58 - </div> 59 - </div> 60 - <div id="gameWrapper" class="gameWrapper"> 61 - <div class="gameContainer skeletonAnimation"></div> 62 - <div class="gameContainer skeletonAnimation"></div> 63 - <div class="gameContainer skeletonAnimation"></div> 64 - <div class="gameContainer skeletonAnimation"></div> 65 - <div class="gameContainer skeletonAnimation"></div> 66 - <div class="gameContainer skeletonAnimation"></div> 67 - <div class="gameContainer skeletonAnimation"></div> 68 - <div class="gameContainer skeletonAnimation"></div> 69 - <div class="gameContainer skeletonAnimation"></div> 70 - <div class="gameContainer skeletonAnimation"></div> 71 - <div class="gameContainer skeletonAnimation"></div> 72 - <div class="gameContainer skeletonAnimation"></div> 73 - <div class="gameContainer skeletonAnimation"></div> 74 - <div class="gameContainer skeletonAnimation"></div> 75 - <div class="gameContainer skeletonAnimation"></div> 76 - <div class="gameContainer skeletonAnimation"></div> 77 - <div class="gameContainer skeletonAnimation"></div> 78 - <div class="gameContainer skeletonAnimation"></div> 79 - <div class="gameContainer skeletonAnimation"></div> 80 - <div class="gameContainer skeletonAnimation"></div> 81 - <h4 class="totalTimeText">0 results in 0ms </h4> 82 - </div> 83 - <div class="pageBarContainer"> 84 - <img class="pageBarImage" id="pageBarBack" onclick="pageBarBack()" src="../images/arrow_back.svg" alt=""> 85 - <p class="pageBarButton" id="pageBarMin" onclick="pageBarMin()">1</p> 86 - <input class="pageBarSearch" id="search3" autocomplete="off" type="number" min="1" placeholder="..." name="fpps4"> 87 - <p class="pageBarButton" id="pageBarMax" onclick="pageBarMax()">1</p> 88 - <img class="pageBarImage" id="pageBarForward" onclick="pageBarForward()" src="../images/arrow_forward.svg" alt=""> 89 - </div> 90 - <h5 style="text-align: center; font-size: 0.8rem;">Trademarks and logos displayed on this website are the property of their respective owners.<br> The use of any third-party trademarks, brand names, product names, and logos is for<br> informational purposes only and does not imply endorsement or sponsorship.</h5> 91 - <br> 92 - </main> 93 - <footer id="footer"> 94 - <style> 95 - footer { 96 - height: 3.65rem; 97 - margin-top: 3rem; 98 - } 99 - </style> 100 - </footer> 101 - <script defer src="app.js"></script> 102 - </body> 16 + <head> 17 + <meta charset="UTF-8"> 18 + <meta http-equiv="X-UA-Compatible" content="IE=edge"> 19 + <meta name="viewport" content="width=device-width, initial-scale=1"> 20 + <title>fpPS4</title> 21 + <meta name="description" content="fpPS4 is an open source PS4 compatibility layer (emulator) written with Free Pascal for Windows."> 22 + <meta name="keywords" content="fpPS4, playstation, ps4, playstation 4, emulator, windows, open source, free pascal, compatibility layer, red-prig, fpps4 github, fpps4 discord"> 23 + <meta name="robots" content="index,follow"> 24 + <meta name="author" content="Mr. Snowy"> 25 + <meta name="copyright" content="fpPS4"> 26 + <meta name="theme-color" content="#4C566A"> 27 + <meta property="og:title" content="fpPS4 - An open source PS4 compatibility layer"> 28 + <meta property="og:description" content="fpPS4 is an open source PS4 compatibility layer written with Free Pascal for Windows."> 29 + <meta property="og:image" content="https://fpps4.net/images/fpPS4Logo.png"> 30 + <meta property="og:url" content="https://fpps4.net"> 31 + <link rel="stylesheet" href="./style.css?v=01"> 32 + <link rel="stylesheet" href="./sizes.css"> 33 + <link rel="icon" href="/_images/fpPS4Logo.png" type="image/png"> 34 + </head> 35 + <body> 36 + <div class="top"> 37 + <div class="top-text-container"> 38 + <h1 class="coming-soon">Work In Progress</h1> 39 + <h1 class="main-text"><span style="color: #f0e74a;">fp</span>PS4</h1> 40 + <p class="progress-text">The offical website for the open-source<br>compatibility layer fpPS4</p> 41 + <div class="topButtonContainer"> 42 + <a href="#learnmore" onclick="scrollToElement(event, 'learnmore')" class="button">Learn more</a> 43 + <a href="https://fpps4.net/compatibility" class="button">Compatibility</a> 44 + </div> 45 + </div> 46 + </div> 47 + <div class="bottom-container" id="learnmore"> 48 + <div class="bottom-left"> 49 + <h1 class="bottom-top-text"><span style="color: #f0e74a;">fp</span>PS4</h1> 50 + <p class="bottom-desc-text">An open-source PS4 compatibility layer (emulator) written with Free Pascal</p> 51 + <div class="buttons-container"> 52 + <a href="https://github.com/red-prig/fpPS4" target="_blank" class="button">Github</a> 53 + <a href="https://discord.gg/up9qatpX7M" target="_blank" class="button">Discord</a> 54 + </div> 55 + </div> 56 + <div class="bottom-right"> 57 + <h1 class="bottom-top-text">Special thanks to:</h1> 58 + <div class="thank-user-container"> 59 + <a href="https://github.com/red-prig" target="_blank"><span style="font-weight: 500;">Red-Prig</span> - For developing <span style="color: #f0e74a;">fp</span>PS4</a> 60 + <a href="https://github.com/georgemoralis" target="_blank"><span style="font-weight: 500;">georgemoralis</span> - For donating the domain</a> 61 + <a href="https://github.com/KimieStar" target="_blank"><span style="font-weight: 500;">KimieStar</span> - For helping with the website</a> 62 + <a href="https://github.com/MrSn0wy" target="_blank"><span style="font-weight: 500;">Mr. Snowy</span> - For making the website :3</a> 63 + </div> 64 + </div> 65 + </div> 66 + </body> 67 + <script src="./app.js"></script> 103 68 </html>
public_html/parts/footer.html public_html/_parts/footer.html
+4 -3
public_html/parts/images/boosty.svg public_html/_images/boosty.svg
··· 1 1 <?xml version="1.0" encoding="utf-8"?> 2 + <!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 2 3 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 3 4 viewBox="0 0 715.8 317.4" style="enable-background:new 0 0 715.8 317.4;" xml:space="preserve"> 4 5 <style type="text/css"> 5 6 .st0{fill:#242B2C;} 6 7 </style> 7 - <g> 8 + <g id="text"> 8 9 <path class="st0" d="M632.8,138.6l-23.1,35.9l-2.3-35.9h-19.3h-6h-7.9c3.1-10.5,5.5-19,5.5-19l1.3-4.2h-25.5l-1.2,4.2l-5.5,19 9 10 h-21.7c-3.6,0-5.4,0-5.4,0c-22.3,0-34.8,6.4-40,18.4c-3-11-12.9-18.4-28.2-18.4c-13.2,0-24.9,4.9-33.6,12.7 10 11 c-4.5-7.8-13.4-12.7-25.8-12.7c-14.2,0-26.5,5.7-35.5,14.4c-4.1-8.7-13.4-14.4-26.7-14.4c-4.6,0-8.9,0.6-13,1.7l2-6.9 ··· 19 20 c-2.2-8.4-11.5-11.8-24.6-13.4c-5.5-0.7-8.6-0.9-7.9-3.3c0.5-1.8,3.3-2.2,9.2-2.2c3.7,0,8.1,0,13.2,0h15.6L537.3,178.6z 20 21 M562.6,178.7c0-0.2,2.5-8.6,5.5-19h16.1l2.6,26.9C560.3,192.3,559.7,190.8,562.6,178.7z"/> 21 22 </g> 22 - <g> 23 - <g> 23 + <g id="sign"> 24 + <g id="b_1_"> 24 25 <path class="st0" d="M87.5,163.9L120.2,51h50.1l-10.1,35c-0.1,0.2-0.2,0.4-0.3,0.6L133.3,179h24.8c-10.4,25.9-18.5,46.2-24.3,60.9 25 26 c-45.8-0.5-58.6-33.3-47.4-72.1 M133.9,240l60.4-86.9h-25.6l22.3-55.7c38.2,4,56.2,34.1,45.6,70.5C225.3,207,179.4,240,134.8,240 26 27 C134.5,240,134.2,240,133.9,240z"/>
-12
public_html/parts/images/boostySmol.svg
··· 1 - <?xml version="1.0" encoding="utf-8"?> 2 - <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 3 - viewBox="0 0 235.6 292.2" style="enable-background:new 0 0 235.6 292.2;" xml:space="preserve"> 4 - <style type="text/css"> 5 - .st0{fill:#242B2C;} 6 - </style> 7 - <g> 8 - <path class="st0" d="M44.3,164.5L76.9,51.6H127l-10.1,35c-0.1,0.2-0.2,0.4-0.3,0.6L90,179.6h24.8c-10.4,25.9-18.5,46.2-24.3,60.9 9 - c-45.8-0.5-58.6-33.3-47.4-72.1 M90.7,240.6l60.4-86.9h-25.6l22.3-55.7c38.2,4,56.2,34.1,45.6,70.5 10 - c-11.3,39.1-57.1,72.1-101.7,72.1C91.3,240.6,91,240.6,90.7,240.6z"/> 11 - </g> 12 - </svg>
-1
public_html/parts/images/close.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-414 282-216q-14 14-33 14t-33-14q-14-14-14-33t14-33l198-198-198-198q-14-14-14-33t14-33q14-14 33-14t33 14l198 198 198-198q14-14 33-14t33 14q14 14 14 33t-14 33L546-480l198 198q14 14 14 33t-14 33q-14 14-33 14t-33-14L480-414Z"/></svg>
public_html/parts/images/dark_mode.svg public_html/_images/dark_mode.svg
-1
public_html/parts/images/discord.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><g id="图层_2" data-name="图层 2"><g id="Discord_Logos" data-name="Discord Logos"><g id="Discord_Logo_-_Large_-_White" data-name="Discord Logo - Large - White"><path d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"/></g></g></g></svg>
+1 -1
public_html/parts/images/github.svg public_html/_images/github.svg
··· 1 - <svg width="98" height="98" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"/></svg> 1 + <svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="black"/></svg>
public_html/parts/images/light_mode.svg public_html/_images/light_mode.svg
-1
public_html/parts/images/menu.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M150-212q-19.75 0-33.375-13.675Q103-239.351 103-259.175 103-279 116.625-292.5 130.25-306 150-306h660q19.75 0 33.375 13.675Q857-278.649 857-258.825 857-239 843.375-225.5 829.75-212 810-212H150Zm0-221q-19.75 0-33.375-13.675Q103-460.351 103-480.175 103-500 116.625-513.5 130.25-527 150-527h660q19.75 0 33.375 13.675Q857-499.649 857-479.825 857-460 843.375-446.5 829.75-433 810-433H150Zm0-221q-19.75 0-33.375-13.675Q103-681.351 103-701.175 103-721 116.625-735 130.25-749 150-749h660q19.75 0 33.375 14.175 13.625 14.176 13.625 34Q857-681 843.375-667.5 829.75-654 810-654H150Z"/></svg>
-1
public_html/parts/images/unused/close.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
-1
public_html/parts/images/unused/dark_mode.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.37 5.51A7.35 7.35 0 0 0 9.1 7.5c0 4.08 3.32 7.4 7.4 7.4.68 0 1.35-.09 1.99-.27A7.014 7.014 0 0 1 12 19c-3.86 0-7-3.14-7-7 0-2.93 1.81-5.45 4.37-6.49zM12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/></svg>
-1
public_html/parts/images/unused/discord-mark-black-crop-opti.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g transform="matrix(.189 0 0 .189 7.79e-5 3)" data-name="图层 2"><g data-name="Discord Logos"><g data-name="Discord Logo - Large - White"><path d="m108 8.07a105 105 0 0 0-26.2-8.07 72.1 72.1 0 0 0-3.36 6.83 97.7 97.7 0 0 0-29.1 0 72.4 72.4 0 0 0-3.36-6.83 106 106 0 0 0-26.2 8.09c-16.6 24.6-21.1 48.5-18.8 72.1a106 106 0 0 0 32.2 16.2 77.7 77.7 0 0 0 6.89-11.1 68.4 68.4 0 0 1-10.8-5.18c0.91-0.66 1.8-1.34 2.66-2a75.6 75.6 0 0 0 64.3 0c0.87 0.71 1.76 1.39 2.66 2a68.7 68.7 0 0 1-10.9 5.19 77 77 0 0 0 6.89 11.1 105 105 0 0 0 32.2-16.1c2.64-27.4-4.51-51.1-18.9-72.2zm-65.2 57.6c-6.27 0-11.4-5.69-11.4-12.7s5-12.7 11.4-12.7 11.6 5.74 11.5 12.7-5.05 12.7-11.4 12.7zm42.2 0c-6.28 0-11.4-5.69-11.4-12.7s5-12.7 11.4-12.7 11.5 5.74 11.4 12.7-5.04 12.7-11.4 12.7z"/></g></g></g></svg>
-1
public_html/parts/images/unused/github-mark-black.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 98"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#000000"/></svg>
-1
public_html/parts/images/unused/menu.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
+6 -6
public_html/parts/navbar.html public_html/_parts/navbar.html
··· 64 64 </a> 65 65 <div class="navbar-right"> 66 66 <a href="https://github.com/red-prig/fpPS4" class="gh-logo"> 67 - <img src="https://fpps4.net/parts/images/github.svg" class="smolImage" alt="Github logo"> 67 + <img src="/_images/github.svg" class="smolImage" alt="Github logo"> 68 68 </a> 69 69 <a href="https://discord.com/invite/up9qatpX7M" target="_blank" class="dc-logo"> 70 - <img src="https://fpps4.net/parts/images/discord.svg" class="smolImage" alt="Discord logo"> 70 + <img src="/_images/discord.svg" class="smolImage" alt="Discord logo"> 71 71 </a> 72 72 <div onclick="toggleMenu()" class="menu-icon"> 73 - <img src="https://fpps4.net/parts/images/menu.svg" id="menu-icon" class="bigImage" alt="Menu button"> 74 - <img src="https://fpps4.net/parts/images/close.svg" id="close-icon" style="display: none;" class="bigImage" alt="Close Menu button"> 73 + <img src="/_images/menu.svg" id="menu-icon" class="bigImage" alt="Menu button"> 74 + <img src="/_images/close.svg" id="close-icon" style="display: none;" class="bigImage" alt="Close Menu button"> 75 75 </div> 76 76 <div onclick="toggleLightMode()" class="lightModeButton"> 77 - <img src="https://fpps4.net/parts/images/dark_mode.svg" id="darkModeIcon" style="opacity: 0;" class="bigImage" alt="Dark mode toggle"> 78 - <img src="https://fpps4.net/parts/images/light_mode.svg" id="lightModeIcon" style="display: none;" class="bigImage" alt="Light mode toggle"> 77 + <img src="/_images/dark_mode.svg" id="darkModeIcon" style="opacity: 0;" class="bigImage" alt="Dark mode toggle"> 78 + <img src="/_images/light_mode.svg" id="lightModeIcon" style="display: none;" class="bigImage" alt="Light mode toggle"> 79 79 </div> 80 80 </div>
+1 -29
public_html/scripts/api.php public_html/_scripts/api.php
··· 3 3 require_once "/home/{$serverUsername}/domains/fpps4.net/config/config.php"; // import config file 4 4 $validSecret = API_ACCESS_SECRET; 5 5 $validArgument = API_ARGUMENT_SECRET; 6 - 7 6 $headers = apache_request_headers(); 8 7 9 - // foreach ($headers as $header => $value) { 10 - 11 - // if ($header === "Token") { 12 - 13 - // if ($value === $validSecret) { 14 - // die('yeey you got in !'); 15 - // } 16 - // } 17 - // } 18 - 19 - 20 8 /// makes it so the api is accessible by: headers, browser query and by command line arguments :3 21 9 if ((isset($_GET[$validArgument]) && $_GET[$validArgument] === $validSecret) || (isset($argv[1]) && $argv[1] === $validSecret) || isset($_SERVER['HTTP_AUTHORIZATION']) === $validSecret) { 22 - 23 10 /// processing user input 24 11 $cusaCodes = isset($_GET['cusa']) ? $_GET['cusa'] : ''; 25 12 $homebrews = isset($_GET['homebrew']) ? $_GET['homebrew'] : ''; 26 - 27 13 $cusaCodes = filter_var($cusaCodes, FILTER_SANITIZE_STRING); 28 14 $homebrews = filter_var($homebrews, FILTER_SANITIZE_STRING); 29 15 30 - 31 - 32 16 if ($cusaCodes || $homebrews) { 33 - 34 17 /// make connection to database 35 18 $host = DATABASE_HOST; 36 19 $database = DATABASE_NAME; 37 20 $username = DATABASE_USERNAME; 38 21 $password = DATABASE_PASSWORD; 39 - 40 22 try { 41 23 $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); 42 24 } catch (PDOException $e) { 43 25 die("The server got itself into trouble, sorry for that."); 44 26 } 45 - 46 27 47 28 /// variables 48 29 $cusacodeArray = array(); 49 30 $homebrewArray = array(); 50 31 $cusacode = explode(',', $cusaCodes); 51 32 $homebrew = explode(',', $homebrews); 52 - 53 33 /// handles cusa codes and gets status 54 34 if ($cusaCodes) { 55 35 foreach ($cusacode as $code) { ··· 58 38 $stmt->bindParam(':cusacode', $code, PDO::PARAM_STR); 59 39 $stmt->execute(); 60 40 $result = $stmt->fetchAll(PDO::FETCH_ASSOC); 61 - // print_r($result); // debug 62 41 63 42 if ($result) { 64 43 $tag = $result["0"]["tags"]; ··· 66 45 $tag = "N/A"; 67 46 } 68 47 69 - // echo "$tag"; // debug 70 48 $cusacodeArray[] = array( 71 49 "id" => $code, 72 50 "tag" => $tag 73 51 ); 74 52 } 75 53 } 76 - 77 54 if ($homebrews) { 78 55 foreach ($homebrew as $code) { 79 56 $query = "SELECT tags FROM issues WHERE title = :homebrew"; ··· 81 58 $stmt->bindParam(':homebrew', $code, PDO::PARAM_STR); 82 59 $stmt->execute(); 83 60 $HBresult = $stmt->fetchAll(PDO::FETCH_ASSOC); 84 - // print_r($HBresult); // debug 85 61 86 62 if ($HBresult) { 87 63 $tag = $HBresult["0"]["tags"]; 88 64 } else { 89 65 $tag = "N/A"; 90 66 } 91 - 92 67 $homebrewArray[] = array( 93 68 "title" => $code, 94 69 "tag" => $tag 95 70 ); 96 71 } 97 72 } 98 - 99 73 $data = array( 100 74 "cusacode" => $cusacodeArray, 101 75 "homebrew" => $homebrewArray 102 76 ); 103 - 104 77 /// end 105 78 header('Content-Type: application/json'); 106 79 $jsonData = json_encode($data); 107 80 //$jsonData = json_encode($data, JSON_PRETTY_PRINT); 81 + 108 82 echo $jsonData; 109 83 $conn = null; //exit connection 110 84 } 111 - 112 - 113 85 } else { 114 86 http_response_code(404); 115 87 include("/home/{$serverUsername}/domains/fpps4.net/public_html/404.php");
-496
public_html/scripts/issue_fetcher.php
··· 1 - <?php 2 - error_reporting(E_ALL); 3 - ini_set('display_errors', '1'); 4 - $serverUsername = getenv('USERNAME'); 5 - require_once "/home/{$serverUsername}/domains/fpps4.net/config/config.php"; // import config file 6 - $validSecret = ACCESS_SECRET; 7 - $validArgument = ARGUMENT_SECRET; 8 - 9 - // The secret query parameter is provided and matches the valid secret 10 - if ((isset($_GET[$validArgument]) && $_GET[$validArgument] === $validSecret) || (isset($argv[1]) && $argv[1] === $validSecret)) { 11 - 12 - $host = DATABASE_HOST; 13 - $username = DATABASE_USERNAME; 14 - $password = DATABASE_PASSWORD; 15 - $database = DATABASE_NAME; 16 - $githubToken = GITHUB_TOKEN; 17 - $tmdbHash = TMDB_HASH; 18 - $homebrewUseragent = HB_USERAGENT; 19 - 20 - try { 21 - // get homebrew db for images 22 - $header = stream_context_create(["http" => ["header" => "User-Agent: $homebrewUseragent\r\n"]]); 23 - $response = file_get_contents("https://api.pkg-zone.com/api.php?db_check_hash=true", false, $header); 24 - if ($response !== false) { 25 - $data = json_decode($response); 26 - $hash = $data->hash; 27 - $md5Hash = md5_file("/home/{$serverUsername}/domains/fpps4.net/public_html/scripts/HBstore.db"); // will give warning on first download 28 - if ($hash === $md5Hash) { 29 - echo("the db is the same! response: $hash local: $md5Hash <br>"); 30 - } else { 31 - echo("the db is diffrent! response: $hash local: $md5Hash downloading db <br>"); 32 - $fileContent = file_get_contents("https://api.pkg-zone.com/store.db", false, $header); 33 - if ($fileContent !== false) { 34 - file_put_contents("/home/{$serverUsername}/domains/fpps4.net/public_html/scripts/HBstore.db", $fileContent) !== false ? die("DB downloaded and saved successfully.<br>") : die("Error saving the downloaded DB.<br>"); 35 - } else { 36 - die("Error downloading the DB from the URL."); 37 - } 38 - } 39 - } else { 40 - echo("Error verifying hash, ignoring for now."); 41 - } 42 - 43 - $dbFile = "/home/{$serverUsername}/domains/fpps4.net/public_html/scripts/HBstore.db"; 44 - try { 45 - $homebrewDB = new PDO("sqlite:$dbFile"); 46 - echo "Connected to the database successfully! <br>"; 47 - } catch (PDOException $e) { 48 - echo "Connection failed: " . $e->getMessage() . "<br>"; 49 - } 50 - 51 - $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); 52 - $conn->query("DROP TABLE IF EXISTS newIssues"); 53 - 54 - // creating tables 55 - $sqlOld = "CREATE TABLE IF NOT EXISTS issues ( 56 - id INT(5) PRIMARY KEY, 57 - cusaCode VARCHAR(10), 58 - title VARCHAR(130), 59 - tags VARCHAR(12), 60 - updatedDate VARCHAR(12) 61 - )"; 62 - 63 - $sqlNew = "CREATE TABLE IF NOT EXISTS newIssues ( 64 - id INT(5) PRIMARY KEY, 65 - cusaCode VARCHAR(10), 66 - title VARCHAR(130), 67 - tags VARCHAR(12), 68 - updatedDate VARCHAR(12) 69 - )"; 70 - 71 - $sqlSkips = "CREATE TABLE IF NOT EXISTS GameSkips ( 72 - code VARCHAR(130) PRIMARY KEY 73 - )"; 74 - 75 - $conn->exec($sqlOld); 76 - $conn->exec($sqlNew); 77 - $conn->exec($sqlSkips); 78 - echo "Tables created successfully.<br>"; 79 - // die("Tables created successfully.<br>"); 80 - 81 - } catch (PDOException $e) { 82 - die("Error creating tables: " . $e->getMessage()); 83 - } 84 - //- creating tables 85 - 86 - function get_open_issues_count() { 87 - global $githubToken; 88 - global $gh_api_total; 89 - 90 - $curl_handle = curl_init(); 91 - curl_setopt($curl_handle, CURLOPT_URL, 'https://api.github.com/repos/red-prig/fpps4-game-compatibility'); 92 - curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('Accept: application/vnd.github+json', 'Authorization: Bearer '.$githubToken)); 93 - curl_setopt($curl_handle, CURLOPT_USERAGENT, "php/curl"); 94 - curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2); 95 - curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); 96 - $buffer = curl_exec($curl_handle); 97 - curl_close($curl_handle); 98 - $data = json_decode($buffer, true); 99 - 100 - $gh_api_total++; 101 - echo "Open issues counted successfully.<br>"; 102 - return $data['open_issues_count']; 103 - } 104 - 105 - function get_open_issues($page) { 106 - global $githubToken; 107 - global $gh_api_total; 108 - 109 - $curl_handle = curl_init(); 110 - curl_setopt($curl_handle, CURLOPT_URL, 'https://api.github.com/repos/red-prig/fpps4-game-compatibility/issues?page='.$page.'&per_page=100&state=open&direction=ASC'); 111 - curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('Accept: application/vnd.github+json', 'Authorization: Bearer '.$githubToken)); 112 - curl_setopt($curl_handle, CURLOPT_USERAGENT, "php/curl"); 113 - curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2); 114 - curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); 115 - $buffer = curl_exec($curl_handle); 116 - curl_close($curl_handle); 117 - 118 - // echo "processed page $page.<br>"; 119 - $gh_api_total++; 120 - return $buffer; 121 - } 122 - 123 - function insert_issue($issue, $conn) { 124 - $id = $issue['number']; 125 - $title = $issue['title']; 126 - $cusaCode = extract_cusaCode($title); 127 - $tags = implode(', ', array_column($issue['labels'], 'name')); 128 - $updatedDate = date('d/m/Y', strtotime($issue['updated_at'])); 129 - 130 - $id = filter_var($id, FILTER_VALIDATE_INT); 131 - $title = filter_var($title, FILTER_SANITIZE_STRING); 132 - $cusaCode = filter_var($cusaCode, FILTER_SANITIZE_STRING); 133 - $tags = filter_var($tags, FILTER_SANITIZE_STRING); 134 - $updatedDate = filter_var($updatedDate, FILTER_SANITIZE_STRING); 135 - 136 - // Handle homebrews and remove CUSA code from the title 137 - if (in_array("app-homebrew", array_column($issue['labels'], 'name'))) { 138 - $cusaCode = "HOMEBREW"; 139 - $clean_title = preg_replace('/\s-\s.*$/', '', $title); 140 - $clean_title = trim(explode('(Homebrew)', $clean_title)[0]); 141 - $clean_title = trim(explode('Homebrew', $clean_title)[0]); 142 - //$clean_title = trim(explode('Game', $clean_title)[0]); 143 - $clean_title = rtrim($clean_title, ' '); 144 - } else if (in_array("app-system-fw505", array_column($issue['labels'], 'name'))){ 145 - $cusaCode = "SYSTEM APP"; 146 - $clean_title = preg_replace('/\s-\s.*$/', '', $title); 147 - } else if (in_array("app-ps2game", array_column($issue['labels'], 'name'))){ 148 - $cusaCode = "PS2 GAME"; 149 - $clean_title = preg_replace('/\s-\s.*$/', '', $title); 150 - } else { 151 - $clean_title = preg_replace('/\b' . preg_quote($cusaCode, '/') . '\b/', '', $title); 152 - $clean_title = preg_replace('/\s+-\s+/', ' - ', $clean_title); 153 - $clean_title = rtrim($clean_title, '- '); 154 - $clean_title = rtrim($clean_title, ' '); 155 - $clean_title = rtrim($clean_title, '[]'); 156 - } 157 - 158 - // Filter labels and give them the correct names 159 - $filteredTags = array_filter($issue['labels'], function ($label) { 160 - return in_array($label['name'], ['status-nothing', 'status-boots', 'status-ingame', 'status-menus', 'status-playable']); 161 - }); 162 - 163 - $tagNames = array_map(function ($label) { 164 - return ucwords(str_replace('status-', '', $label['name'])); 165 - }, $filteredTags); 166 - 167 - if (empty($tagNames)) { 168 - $tagNames = ['N/A']; 169 - } else { 170 - // Define the order of the tags 171 - $tagOrder = [ 172 - 'status-playable', 173 - 'status-ingame', 174 - 'status-menus', 175 - 'status-boots', 176 - 'status-nothing' 177 - ]; 178 - 179 - // Sort the tags 180 - usort($tagNames, function ($a, $b) use ($tagOrder) { 181 - return array_search($a, $tagOrder) <=> array_search($b, $tagOrder); 182 - }); 183 - 184 - // Take the best tag 185 - $tagNames = array_slice($tagNames, 0, 1); 186 - } 187 - 188 - $tags = implode(', ', $tagNames); 189 - 190 - // Use prepared statement to insert data into the database 191 - $insert_query = "INSERT INTO newIssues (id, cusaCode, title, tags, updatedDate) VALUES (:id, :cusaCode, :clean_title, :tags, :updatedDate)"; 192 - $stmt = $conn->prepare($insert_query); 193 - $stmt->bindParam(':id', $id, PDO::PARAM_INT); 194 - $stmt->bindParam(':cusaCode', $cusaCode, PDO::PARAM_STR); 195 - $stmt->bindParam(':clean_title', $clean_title, PDO::PARAM_STR); 196 - $stmt->bindParam(':tags', $tags, PDO::PARAM_STR); 197 - $stmt->bindParam(':updatedDate', $updatedDate, PDO::PARAM_STR); 198 - 199 - if (!$stmt->execute()) { 200 - die("Error inserting issue: " . $stmt->errorInfo()[2]); 201 - } 202 - } 203 - 204 - function extract_cusaCode($title) { 205 - preg_match('/CUSA[0-9]{5,}/', $title, $matches); 206 - if (!empty($matches)) { 207 - return $matches[0]; 208 - } 209 - 210 - return null; 211 - } 212 - 213 - // Images logic 214 - function get_image($cusaCode, $homebrewDB) { 215 - global $issue; 216 - global $serverUsername; 217 - global $conn; 218 - global $homebrewUseragent; 219 - //global $homebrewDB; 220 - $iconUrl = ''; 221 - $avifIconURL = ''; 222 - echo " DEBUG: $cusaCode"; 223 - 224 - try { 225 - if (in_array("app-homebrew", array_column($issue['labels'], 'name'))) { 226 - 227 - $query = "SELECT image FROM homebrews WHERE name = :name"; 228 - $statement = $homebrewDB->prepare($query); 229 - $statement->bindParam(':name', $cusaCode); 230 - $statement->execute(); 231 - $result = $statement->fetch(PDO::FETCH_ASSOC); 232 - //var_dump("image link: $result <br>"); 233 - //echo "image link: $result <br>" ; 234 - // if ($result !== false) { 235 - if (!empty($result)) { 236 - $iconUrl = $result['image']; 237 - //echo "Image link: $iconUrl<br>"; 238 - var_dump("image link: $iconUrl <br>"); 239 - $avifIconURL = "/home/{$serverUsername}/domains/fpps4.net/public_html/images/HOMEBREW/{$cusaCode}.avif"; 240 - $header = stream_context_create(["http" => ["header" => "User-Agent: $homebrewUseragent\r\n"]]); 241 - $httpsIconUrl = str_replace('http://', 'https://', $iconUrl); 242 - $imageData = file_get_contents($httpsIconUrl, false, $header); 243 - } else { 244 - echo "No record found for the given name.<br>"; 245 - throw new Exception(); 246 - } 247 - // } else {throw new Exception();} 248 - } else { 249 - global $tmdbHash; 250 - $key = hex2bin($tmdbHash); 251 - $hashme = $cusaCode . '_00'; 252 - $hash = strtoupper(hash_hmac('sha1', $hashme, $key)); 253 - $url = "https://tmdb.np.dl.playstation.net/tmdb2/{$cusaCode}_00_{$hash}/{$cusaCode}_00.json"; 254 - $userAgent = 'Mozilla/5.0 (PlayStation; PlayStation 4/10.71) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15'; 255 - $PS4header = stream_context_create(["http" => ["header" => "User-Agent: $userAgent\r\n"]]); // ps4 useragent cuz im silly 256 - $headers = get_headers($url, false, $PS4header); 257 - if ($headers !== false && strpos($headers[0], '200') !== false) { 258 - $response = file_get_contents($url, false, $PS4header); 259 - if ($response !== false) { 260 - $data = json_decode($response, true); 261 - if (isset($data['icons']) && is_array($data['icons']) && count($data['icons']) > 0) { 262 - $iconUrl = $data['icons'][0]['icon']; 263 - $avifIconURL = "/home/{$serverUsername}/domains/fpps4.net/public_html/images/CUSA/{$cusaCode}.avif"; 264 - $httpsIconUrl = str_replace('http://', 'https://', $iconUrl); 265 - $imageData = file_get_contents($httpsIconUrl, false, $PS4header); 266 - } else {throw new Exception();} 267 - } else {throw new Exception();} 268 - } else {throw new Exception();} 269 - } 270 - 271 - 272 - $imagick = new Imagick(); 273 - if ($imagick->readImageBlob($imageData)) { 274 - $imageFormat = $imagick->getImageFormat(); 275 - if ($imageFormat == 'JPEG' || $imageFormat == 'PNG') { 276 - $imagick->setImageFormat('avif'); 277 - $imagick->setCompressionQuality(75); 278 - $imagick->setImageProperty('avif:effort', '10'); 279 - $imagick->setImageProperty('avif:speed', '8'); 280 - $imagick->thumbnailImage(128, 128, true); 281 - $imagick->setImageProperty('avif:strip', ''); 282 - $imagick->writeImage($avifIconURL); // save the image 283 - } 284 - } 285 - $imagick->clear(); 286 - $imagick->destroy(); 287 - 288 - } catch (Exception $e) { 289 - echo "<p style='color: red;'>$cusaCode got an error while downloading, $e </p><br>"; 290 - $columnName = "code"; 291 - $insertQuery = "INSERT INTO GameSkips ($columnName) VALUES (:value1)"; 292 - $stmt = $conn->prepare($insertQuery); 293 - $stmt->bindParam(':value1', $cusaCode, PDO::PARAM_STR); 294 - if (!$stmt->execute()) { 295 - die("Error inserting issue: " . $stmt->errorInfo()[2]); 296 - } 297 - } 298 - } 299 - //- Images logic 300 - 301 - $gh_api_total = 0; 302 - $open_issues_count = get_open_issues_count(); 303 - $total_pages = ceil($open_issues_count / 100); 304 - $total_processed = 0; 305 - $total_skipped = 0; 306 - $CUSA_total_skipped = 0; 307 - $images_downloaded = 0; 308 - $images_skiped = 0; 309 - $homebrewProcessed = 0; 310 - $systemProcessed = 0; 311 - $ps2Processed = 0; 312 - $HB_images_downloaded = 0; 313 - $HB_images_skiped = 0; 314 - 315 - for ($page = 1; $page <= $total_pages; $page++) { 316 - $issues_data = get_open_issues($page); 317 - $issues_array = json_decode($issues_data, true); 318 - 319 - foreach ($issues_array as $issue) { 320 - $title = $issue['title']; 321 - $cusaCode = extract_cusaCode($title); 322 - $avifIconURL = "/home/{$serverUsername}/domains/fpps4.net/public_html/images/CUSA/{$cusaCode}.avif"; 323 - 324 - // Check if cusa code is not empty 325 - if ($cusaCode) { 326 - $query = "SELECT cusaCode FROM newIssues WHERE cusaCode = :cusaCode"; 327 - $stmt = $conn->prepare($query); 328 - $stmt->bindParam(':cusaCode', $cusaCode, PDO::PARAM_STR); 329 - $stmt->execute(); 330 - $check_result = $stmt->fetchAll(PDO::FETCH_ASSOC); 331 - 332 - if (count($check_result) > 0) { 333 - $total_skipped++; 334 - // echo "Duplicate found: " . $cusaCode . "<br>"; // echo duplicates 335 - continue; 336 - } 337 - $total_processed++; 338 - insert_issue($issue, $conn); 339 - 340 - if (!file_exists($avifIconURL)) { // check for images 341 - // ECHO "<br> DEBUG: I AM GETTING CHECKED. $cusaCode <br>"; 342 - $query = "SELECT code FROM GameSkips WHERE code = :code"; 343 - $stmt = $conn->prepare($query); 344 - $stmt->bindParam(':code', $cusaCode, PDO::PARAM_STR); 345 - $stmt->execute(); 346 - // ECHO "<br> DEBUG: I HAVE BEEN CHECKED. $cusaCode <br>"; 347 - 348 - if ($stmt->rowCount() > 0) { 349 - $images_skiped++; 350 - continue; 351 - // ECHO "<br> DEBUG: I HAVE BEEN SKIPPED. $cusaCode <br>"; 352 - } else { 353 - get_image($cusaCode, $homebrewDB); // Download image 354 - $images_downloaded++; 355 - // ECHO "<br> DEBUG: I HAVE BEEN DOWNLOADED. $cusaCode <br>"; 356 - } 357 - } else { 358 - $images_skiped++; 359 - } 360 - 361 - // HOMEBREW GAMES/APPS 362 - } else if (in_array("app-homebrew", array_column($issue['labels'], 'name'))) { 363 - $hb_title = preg_replace('/\s-\s.*$/', '', $title); 364 - $hb_title = trim(explode('(Homebrew)', $hb_title)[0]); 365 - $hb_title = trim(explode('Homebrew', $hb_title)[0]); 366 - //$hb_title = trim(explode('Game', $hb_title)[0]); 367 - $hb_title = rtrim($hb_title, ' '); 368 - 369 - $query = "SELECT title FROM newIssues WHERE title = :title"; 370 - $stmt = $conn->prepare($query); 371 - $stmt->bindParam(':title', $hb_title, PDO::PARAM_STR); 372 - $stmt->execute(); 373 - $checkTitle = $stmt->fetchAll(PDO::FETCH_ASSOC); 374 - if (count($checkTitle) > 0) { 375 - $total_skipped++; 376 - continue; 377 - } 378 - 379 - if (!file_exists("/home/{$serverUsername}/domains/fpps4.net/public_html/images/HOMEBREW/{$hb_title}.avif")) { // check for images 380 - // $query = "SELECT cusaCode FROM GameSkips WHERE homeBrew = :homeBrew"; 381 - $query = "SELECT code FROM GameSkips WHERE code = :code"; 382 - $stmt = $conn->prepare($query); 383 - $stmt->bindParam(':code', $hb_title, PDO::PARAM_STR); 384 - $stmt->execute(); 385 - $check_result = $stmt->fetchAll(PDO::FETCH_ASSOC); 386 - 387 - if (count($check_result) > 0) { 388 - $HB_images_skiped++; 389 - // echo "$hb_title is skipped <br>"; 390 - } else { 391 - get_image($hb_title, $homebrewDB); // Download image 392 - $HB_images_downloaded++; 393 - // echo "$hb_title getting downloaded <br>"; 394 - } 395 - } else { 396 - $HB_images_skiped++; 397 - // echo "$hb_title exists <br>"; 398 - } 399 - 400 - insert_issue($issue, $conn); 401 - $total_processed++; 402 - $homebrewProcessed++; 403 - 404 - } else if (in_array("app-system-fw505", array_column($issue['labels'], 'name'))){ 405 - $query = "SELECT title FROM newIssues WHERE title = :title"; 406 - $stmt = $conn->prepare($query); 407 - $stmt->bindParam(':title', $title, PDO::PARAM_STR); 408 - $stmt->execute(); 409 - $checkTitle = $stmt->fetchAll(PDO::FETCH_ASSOC); 410 - 411 - if (count($checkTitle) > 0) { 412 - $total_skipped++; 413 - continue; 414 - } 415 - $total_processed++; 416 - $systemProcessed++; 417 - insert_issue($issue, $conn); 418 - 419 - } else if (in_array("app-ps2game", array_column($issue['labels'], 'name'))){ 420 - $query = "SELECT title FROM newIssues WHERE title = :title"; 421 - $stmt = $conn->prepare($query); 422 - $stmt->bindParam(':title', $title, PDO::PARAM_STR); 423 - $stmt->execute(); 424 - $checkTitle = $stmt->fetchAll(PDO::FETCH_ASSOC); 425 - 426 - if (count($checkTitle) > 0) { 427 - $total_skipped++; 428 - continue; 429 - } 430 - $total_processed++; 431 - $ps2Processed++; 432 - insert_issue($issue, $conn); 433 - } else { 434 - $CUSA_total_skipped++; 435 - //echo "<a href='https://github.com/red-prig/fpps4-game-compatibility/issues/" . $issue['number'] . "' target='_blank'>https://github.com/red-prig/fpps4-game-compatibility/issues/" . $issue['number'] . "</a><br>"; 436 - continue; 437 - } 438 - } 439 - } 440 - 441 - // Check if newIssues table is empty 442 - $result = $conn->query("SELECT COUNT(*) as count FROM newIssues"); 443 - if ($result === false) { 444 - die("Error checking table: " . $conn->errorInfo()[2]); 445 - } 446 - echo "newIssues checked succesfully<br>"; 447 - 448 - $data_count = $result->fetchColumn(); 449 - if ($data_count > 0) { 450 - echo "newIssues is full<br>"; 451 - 452 - $dropOldTable = $conn->query("DELETE FROM issues"); 453 - if ($dropOldTable === false) { 454 - die("Error dropping table: " . $conn->errorInfo()[2]); 455 - } 456 - echo "oldIssues emptied succesfully<br>"; 457 - 458 - // move new issues to old issues + cleanup 459 - $moveResult = $conn->query("INSERT INTO issues (id, cusaCode, title, tags, updatedDate) SELECT id, cusaCode, title, tags, updatedDate FROM newIssues"); 460 - if ($moveResult === false) { 461 - die("Error moving data to issues table: " . $conn->errorInfo()[2]); 462 - } 463 - echo "Moved all issues succesfully<br>"; 464 - 465 - // drop newIssues table 466 - $dropNewTable = $conn->query("DROP TABLE IF EXISTS newIssues"); 467 - if ($dropNewTable === false) { 468 - die("Error dropping table: " . $conn->errorInfo()[2]); 469 - } 470 - echo "newIssues emptied succesfully<br>"; 471 - } else { 472 - print "<br>error: No issues found in newIssues. "; 473 - } 474 - $conn = null; 475 - 476 - // print debug stuff 477 - print "<br>done :D"; 478 - print "<br>Total pages: " . $total_pages; 479 - print "<br>Total open issues: " . $open_issues_count; 480 - print "<br>Total issues without CUSA: " . $CUSA_total_skipped; 481 - print "<br>Total issues processed: " . $total_processed; 482 - print "<br>Homebrew's processed: " . $homebrewProcessed; 483 - print "<br>System Apps processed: " . $systemProcessed; 484 - print "<br>PS2 Games processed: " . $ps2Processed; 485 - print "<br>Total duplicates: " . $total_skipped; 486 - print "<br>Total images downloaded: " . $images_downloaded; 487 - print "<br>Total images skipped: " . $images_skiped; 488 - print "<br>Total homebrew images downloaded: " . $HB_images_downloaded; 489 - print "<br>Total homebrew images skipped: " . $HB_images_skiped; 490 - print "<br>Total github api requests: " . $gh_api_total; 491 - 492 - // Fake 404 page vv 493 - } else { 494 - http_response_code(404); 495 - include("/home/{$serverUsername}/domains/fpps4.net/public_html/404.php"); 496 - }?>
-186
public_html/scripts/search.php
··· 1 - <?php 2 - // I try to make my code as easy to understand as possible. 3 - // When there is a comment "//" that useally means that that part of the code starts there until the next comment. 4 - 5 - /// timer 6 - $startTime = microtime(true); 7 - 8 - 9 - /// connecting to database 10 - $serverUsername = getenv('USERNAME'); 11 - require_once "/home/{$serverUsername}/domains/fpps4.net/config/config.php"; // import config file 12 - 13 - $host = DATABASE_HOST; 14 - $database = DATABASE_NAME; 15 - $username = DATABASE_USERNAME; 16 - $password = DATABASE_PASSWORD; 17 - 18 - try { 19 - $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); 20 - } catch (PDOException $e) { 21 - echo "The server got itself into trouble, please try to refresh.<br>"; 22 - } 23 - 24 - 25 - /// processing user input 26 - $searchQuery = isset($_GET['q']) ? $_GET['q'] : ''; 27 - $tags = isset($_GET['tag']) ? $_GET['tag'] : ''; 28 - $page = isset($_GET['page']) ? $_GET['page'] : 1; 29 - $oldest = isset($_GET['oldest']) ? $_GET['oldest'] : false; 30 - $giveStats = isset($_GET['stats']) ? true : false; 31 - 32 - $searchQuery = filter_var($searchQuery, FILTER_SANITIZE_STRING); 33 - $tags = filter_var($tags, FILTER_SANITIZE_STRING); 34 - $page = filter_var($page, FILTER_VALIDATE_INT); 35 - $oldest = filter_var($oldest, FILTER_VALIDATE_BOOLEAN); 36 - $giveStats = filter_var($giveStats, FILTER_VALIDATE_BOOLEAN); 37 - 38 - 39 - /// defining stuff lmao 40 - $maxResults = (!empty($searchQuery)) ? 10 : 20; 41 - $pageNumber = ($page - 1) * $maxResults; 42 - $sqlQuery = "SELECT * FROM issues"; 43 - $params = array(); 44 - $conditions = array(); 45 - 46 - 47 - /// if there is an search query in the request 48 - if (!empty($searchQuery)) { 49 - $searchQuery = strtolower($searchQuery); 50 - if (strpos($searchQuery, 'cusa') !== false) { 51 - $conditions[] = "cusaCode LIKE :searchQuery"; 52 - } else { 53 - $conditions[] = "title LIKE :searchQuery"; 54 - } 55 - $params[':searchQuery'] = $searchQuery . '%'; 56 - } 57 - 58 - 59 - /// if there are tags in the request 60 - if (!empty($tags)) { 61 - $tagFilters = explode(',', $tags); 62 - $tagConditions = []; 63 - $tagParams = []; 64 - 65 - foreach ($tagFilters as $index => $tag) { 66 - $tagParam = ":tagFilter{$index}"; 67 - $tagConditions[] = "(CONCAT(',', tags, ',') LIKE CONCAT('%,', {$tagParam}, ',%'))"; 68 - $tagParams[$tagParam] = "{$tag}"; 69 - } 70 - 71 - if (!empty($tagConditions)) { 72 - $conditions[] = "(" . implode(" OR ", $tagConditions) . ")"; 73 - $params = array_merge($params, $tagParams); 74 - } 75 - } 76 - 77 - 78 - /// im too lazy to write a comment 79 - if (!empty($conditions)) { 80 - $sqlQuery .= " WHERE " . implode(" AND ", $conditions); 81 - } 82 - 83 - 84 - /// gets the total amount of issues based on the search query 85 - $sqlQueryForTotal = "SELECT COUNT(*) AS total FROM ($sqlQuery) AS totalIssues"; 86 - $stmtTotal = $conn->prepare($sqlQueryForTotal); 87 - 88 - foreach ($params as $param => &$value) { 89 - $stmtTotal->bindParam($param, $value, PDO::PARAM_STR); 90 - } 91 - 92 - $stmtTotal->execute(); 93 - $totalIssuesAmount = $stmtTotal->fetch(PDO::FETCH_ASSOC)['total']; 94 - $totalPages = ceil($totalIssuesAmount / $maxResults); 95 - echo "<div id='totalPages' data='{$totalPages}'></div>"; 96 - if ($totalIssuesAmount < 1) { 97 - echo "<p class='noResultsText'>No results found based on your query</p>"; 98 - echo "<p class='noResultsEmoji'>¯\_(ツ)_/¯</p>"; 99 - } 100 - 101 - /// forming and executing sql query 102 - $sqlQuery .= " ORDER BY id " . ($oldest ? "ASC" : "DESC"); 103 - $sqlQuery .= " LIMIT :offset, :limit"; 104 - $params[':offset'] = $pageNumber; 105 - $params[':limit'] = $maxResults; 106 - 107 - $stmt = $conn->prepare($sqlQuery); 108 - 109 - foreach ($params as $param => &$value) { 110 - if (is_int($value)) { 111 - $stmt->bindParam($param, $value, PDO::PARAM_INT); 112 - } else { 113 - $stmt->bindParam($param, $value, PDO::PARAM_STR); 114 - } 115 - } 116 - 117 - $stmt->execute(); 118 - $result = $stmt->fetchAll(PDO::FETCH_ASSOC); 119 - 120 - 121 - /// Outputing results 122 - foreach ($result as $row) { 123 - $id = $row['id']; 124 - $cusaCode = $row['cusaCode']; 125 - $clean_title = $row['title']; 126 - $tags = $row['tags']; 127 - $updatedAt = $row['updatedDate']; 128 - 129 - $dataCusa = ''; 130 - $avifIconURL = "../images/CUSA/{$cusaCode}.avif"; 131 - if (!file_exists($avifIconURL)) { 132 - $dataCusa = null; // Skip image 133 - } else { 134 - $dataCusa = $cusaCode; 135 - } 136 - 137 - echo "<div class='gameContainer'>"; 138 - echo "<a data-id='$id' class='gameImageLink'>"; 139 - echo "<img class='gameImage' data-cusa='$dataCusa' alt='$clean_title'>"; 140 - echo "</a>"; 141 - echo "<div class='gameSeparator'></div>"; 142 - echo "<div class='gameDetails'>"; 143 - echo "<p class='gameName'>$clean_title</p>"; 144 - echo "<p data='$updatedAt' class='gameCusa'>$cusaCode</p>"; 145 - echo "<p class='gameStatus'>$tags</p>"; 146 - echo "</div>"; 147 - echo "</div>"; 148 - } 149 - 150 - 151 - /// stats on the compatibility list 152 - if ($giveStats === true) { 153 - $availableTags = ['N/A', 'Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; 154 - $tagPercentages = []; 155 - 156 - $stmt = $conn->prepare("SELECT COUNT(*) AS total FROM issues"); 157 - $stmt->execute(); 158 - $total = $stmt->fetch(PDO::FETCH_ASSOC)['total']; 159 - 160 - foreach ($availableTags as $tag) { 161 - $stmt = $conn->prepare("SELECT COUNT(*) AS count FROM issues WHERE tags = :tag"); 162 - $stmt->bindParam(':tag', $tag, PDO::PARAM_STR); 163 - $stmt->execute(); 164 - 165 - $count = $stmt->fetch(PDO::FETCH_ASSOC)['count']; 166 - $percentage = ($total > 0) ? ($count / $total) * 100 : 0; 167 - $tagPercentages[$tag] = $percentage; 168 - $tagCount[$tag] = $count; 169 - } 170 - 171 - $amount = (100 - array_sum($tagPercentages)) / count($tagPercentages); 172 - 173 - foreach ($tagPercentages as $tag => $percentage) { 174 - $percentage += $amount; 175 - $percentage = round($percentage, 2); 176 - echo "<div id='$tag' data='$percentage+$tagCount[$tag]'></div>"; 177 - } 178 - } 179 - 180 - 181 - /// end 182 - $conn = null; //exit connection 183 - $endTime = microtime(true); 184 - $executionTime = round(($endTime - $startTime) * 1000, 2); // Convert to milliseconds 185 - echo "<h4 class= 'totalTimeText'>$totalIssuesAmount results in {$executionTime}ms </h4>"; 186 - ?>
+2 -2
public_html/sizes.css
··· 87 87 padding: 9px 0; 88 88 width: 116px; 89 89 height: 42px; 90 - font-size: 14px; 90 + font-size: 16px; 91 91 } 92 92 93 93 .bottom-top-text { ··· 207 207 padding: 7px 0; 208 208 width: 100px; 209 209 height: 34px; 210 - font-size: 12px; 210 + font-size: 14px; 211 211 } 212 212 213 213 .bottom-desc-text {
+18 -10
public_html/style.css
··· 1 + @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;500&display=swap'); 1 2 /*+ scrollbar */ 2 3 ::-webkit-scrollbar { 3 4 width: 0.57rem;} ··· 25 26 margin: 0; 26 27 padding: 0; 27 28 box-sizing: border-box; 28 - font-family: 'Montserrat', sans-serif; 29 + font-family: 'Rubik', sans-serif; 29 30 color: var(--text); 30 31 text-decoration: none; 31 32 scrollbar-color: var(--main1) #ffffff00; /* - FF scrollbar */ 32 33 text-rendering: optimizeLegibility; 33 34 -webkit-tap-highlight-color: transparent; 35 + font-weight: 400; 34 36 } 35 37 36 38 html {scroll-behavior: smooth; transition: all ease 0.4s;} ··· 69 71 position: absolute; 70 72 top: 16%; 71 73 font-size:32px; 74 + font-weight: 500; 72 75 } 73 76 74 77 .main-text { ··· 76 79 position: absolute; 77 80 top: 35%; 78 81 font-size: 42px; 82 + font-weight: 500; 79 83 } 80 84 81 85 ··· 87 91 } 88 92 89 93 .button { 90 - cursor: pointer; 91 - position: relative; 92 - width: 130px; 93 - height: 50px; 94 - padding: 12px 0; 95 - text-align: center; 96 - border-radius: 8px; 97 - font-size: 16px; 98 - border: 2px solid var(--solidBorder); 94 + cursor: pointer; 95 + position: relative; 96 + width: 130px; 97 + height: 50px; 98 + padding: 12px 0; 99 + border-radius: 8px; 100 + font-size: 16px; 101 + border: 2px solid var(--solidBorder); 102 + display: flex; 103 + align-content: center; 104 + flex-wrap: wrap; 105 + justify-content: center; 99 106 } 100 107 101 108 .topButtonContainer { ··· 150 157 position: absolute; 151 158 top: 20%; 152 159 font-size: 39px; 160 + font-weight: 500; 153 161 } 154 162 155 163 .bottom-desc-text {
public_html/styles.css

This is a binary file and will not be displayed.