automated terminal push
This commit is contained in:
32
.gitignore
vendored
32
.gitignore
vendored
@@ -1,15 +1,27 @@
|
||||
# ---> Linux
|
||||
*~
|
||||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
/target/
|
||||
|
||||
11
.legacy/.dockerignore
Normal file
11
.legacy/.dockerignore
Normal file
@@ -0,0 +1,11 @@
|
||||
volumes/
|
||||
|
||||
.git
|
||||
|
||||
.pristine
|
||||
|
||||
.trash
|
||||
|
||||
.recycle
|
||||
|
||||
.backup
|
||||
15
.legacy/.gitignore
vendored
Normal file
15
.legacy/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# ---> Linux
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
17
.legacy/Dockerfile
Normal file
17
.legacy/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM maven:3.8.7-openjdk-18-slim AS mavenBuild
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mvn install -DskipTests
|
||||
|
||||
FROM eclipse-temurin:18-jre-alpine
|
||||
|
||||
COPY --from=mavenBuild /target/yankee-gnome-twitch-api-1.0.jar /yankee-gnome-twitch-api.jar
|
||||
|
||||
COPY --from=mavenBuild /src/main/resources/application.properties /application.properties
|
||||
|
||||
COPY --from=mavenBuild /src/main/resources/eighteen.stub.html /eighteen.stub.html
|
||||
|
||||
CMD ["java", "-jar", "/yankee-gnome-twitch-api.jar"]
|
||||
32
.legacy/compose.bash
Executable file
32
.legacy/compose.bash
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
##
|
||||
|
||||
set -e
|
||||
|
||||
set -x
|
||||
|
||||
##
|
||||
|
||||
reset
|
||||
|
||||
clear
|
||||
|
||||
##
|
||||
|
||||
echo
|
||||
echo "STARTED / yankee / twitchtracker / channel rankings"
|
||||
echo
|
||||
|
||||
|
||||
##
|
||||
|
||||
docker compose down --remove-orphans
|
||||
|
||||
#git pull
|
||||
|
||||
docker compose up --build -d
|
||||
|
||||
echo
|
||||
echo "RUNNING / yankee / twitchtracker / channel rankings"
|
||||
echo
|
||||
91
.legacy/compose.yaml
Normal file
91
.legacy/compose.yaml
Normal file
@@ -0,0 +1,91 @@
|
||||
services:
|
||||
|
||||
yankee-gnome-twitch-api:
|
||||
|
||||
container_name: yankee-gnome-twitch-api
|
||||
|
||||
image: valorantdigital/yankee-gnome-twitch-api
|
||||
|
||||
build:
|
||||
|
||||
context: .
|
||||
|
||||
dockerfile: Dockerfile
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
|
||||
- 8888:8888
|
||||
|
||||
environment:
|
||||
|
||||
DB_HOST: yankee-database-server
|
||||
|
||||
DB_PORT: 3306
|
||||
|
||||
DB_NAME: yankee
|
||||
|
||||
DB_USER: yankee
|
||||
|
||||
DB_PASS: yankee
|
||||
|
||||
VIRTUAL_PORT: 8888
|
||||
|
||||
VIRTUAL_HOST: apis.yankee.embanet.online
|
||||
|
||||
LETSENCRYPT_HOST: apis.yankee.embanet.online
|
||||
|
||||
##########################################
|
||||
##
|
||||
## veneno / relational data
|
||||
##
|
||||
##########################################
|
||||
|
||||
veneno-database:
|
||||
|
||||
container_name: veneno-database
|
||||
|
||||
image: mariadb:latest
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
|
||||
- "3306:3306"
|
||||
|
||||
environment:
|
||||
|
||||
MYSQL_ROOT_PASSWORD: aggiepride
|
||||
|
||||
MYSQL_DATABASE: yankee_gnome_twitch
|
||||
|
||||
MYSQL_USER: yankee_gnome_twitch
|
||||
|
||||
MYSQL_PASSWORD: yankee_gnome_twitch
|
||||
|
||||
volumes:
|
||||
|
||||
- /yankee/volumes/database:/var/lib/mysql
|
||||
|
||||
veneno-phpmyadmin:
|
||||
|
||||
container_name: veneno-phpmyadmin
|
||||
|
||||
image: beeyev/phpmyadmin-lightweight
|
||||
|
||||
depends_on:
|
||||
|
||||
- veneno-database
|
||||
|
||||
links:
|
||||
|
||||
- veneno-database
|
||||
|
||||
environment:
|
||||
|
||||
PMA_HOST: veneno-database
|
||||
|
||||
VIRTUAL_HOST: database.yankee.embanet.online
|
||||
|
||||
LETSENCRYPT_HOST: database.yankee.embanet.online
|
||||
14
.legacy/docs/api/twitch/channel.md
Normal file
14
.legacy/docs/api/twitch/channel.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# API
|
||||
|
||||
http://localhost:8888/twitch/channel/truncate
|
||||
|
||||
## load the top 1000
|
||||
|
||||
go get 50x rankings, 20 times. truncates before all operations.
|
||||
|
||||
localhost:8888/twitchtracker.com/channel/load/
|
||||
|
||||
##
|
||||
http://localhost:8888/twitchtracker.com/channel/load/2
|
||||
|
||||
load page two of the rankings
|
||||
65
.legacy/docs/api/twitch/twitchdata.com/stub.md
Normal file
65
.legacy/docs/api/twitch/twitchdata.com/stub.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# TwitchTrackerStubController API Documentation
|
||||
|
||||
This document outlines the functionalities provided by the `TwitchTrackerStubController` class.
|
||||
|
||||
**Note:** This API provides stubbed data, meaning it simulates real data from `twitchtracker.com` but doesn't interact with the actual website.
|
||||
|
||||
**Base URL:** `http://localhost:8888/twitchtracker.com/channel/stub`
|
||||
|
||||
**CORS:** Enabled
|
||||
|
||||
### Endpoints
|
||||
|
||||
#### 1. GET /rankings
|
||||
|
||||
* **Description:** This endpoint retrieves a single page (50 channels) of stubbed Twitch channel rankings data.
|
||||
* **Response:** String containing HTML data representing the rankings table.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```
|
||||
GET http://localhost:8888/twitchtracker.com/channel/stub/rankings
|
||||
```
|
||||
|
||||
#### 2. GET /load/
|
||||
|
||||
* **Description:** This endpoint fetches and returns a list of 1000 stubbed Twitch channels with their rankings.
|
||||
* **Response:** List of `TwitchChannel` objects containing channel information.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```
|
||||
GET http://localhost:8888/twitchtracker.com/channel/stub/load/
|
||||
```
|
||||
|
||||
**Implementation Details:**
|
||||
|
||||
* This endpoint calculates the number of pages required to retrieve 1000 channels based on the `channelsPerTwitchTrackerPage` constant (default 50).
|
||||
* It then iterates through each page number and calls the `loadSingleTwitchTrackerPageByNumber` endpoint to retrieve the data.
|
||||
* Finally, it combines all retrieved channels into a single list and returns it.
|
||||
|
||||
#### 3. GET /load/{pageNumber}
|
||||
|
||||
* **Description:** This endpoint retrieves a single page (50 channels) of stubbed Twitch channel rankings data based on the provided page number.
|
||||
* **Path Variable:** `pageNumber` (integer) - Specifies the desired page number.
|
||||
* **Response:** List of `TwitchChannel` objects containing channel information for the requested page.
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```
|
||||
GET http://localhost:8888/twitchtracker.com/channel/stub/load/2
|
||||
```
|
||||
|
||||
**Implementation Details:**
|
||||
|
||||
* This endpoint fetches a single page of stubbed HTML data representing the rankings table.
|
||||
* It then parses the HTML and converts it into a list of `TwitchChannel` objects using the `twitchTrackerService.convert_html_list_twitch_channels` method.
|
||||
* Finally, it saves each retrieved channel to the database using the `twitchChannelService.save` method. (This behavior might be specific to your application's use case.)
|
||||
|
||||
|
||||
**Additional Notes:**
|
||||
|
||||
* The `sleepRandomly` method introduces a random delay between page fetches to simulate realistic network behavior.
|
||||
* This documentation assumes familiarity with Spring annotations like `@GetMapping`, `@PathVariable`, and `@Autowired`.
|
||||
|
||||
|
||||
40
.legacy/docs/golive.md
Normal file
40
.legacy/docs/golive.md
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
1. log in to linux server
|
||||
2. clone repository
|
||||
|
||||
```
|
||||
https://code.softwareshinobi.digital/yankee/twitchtracker-channel-rankings.git
|
||||
``
|
||||
|
||||
3. go into directory
|
||||
|
||||
4.
|
||||
|
||||
|
||||
docker compose.bash
|
||||
|
||||
it is assumed you already have docker installerd.
|
||||
|
||||
so then run
|
||||
|
||||
```
|
||||
sudo bash provision.bash
|
||||
```
|
||||
|
||||
## load the fake data to spec first
|
||||
|
||||
http://aventador.embanet.softwareshinobi.digital:48888/twitchtracker.com/channel/stub/load/
|
||||
|
||||
## populate the sql query to load the view
|
||||
|
||||
|
||||
|
||||
|
||||
## database loging
|
||||
|
||||
phpmyadmin, lets you manage shit inside the db.
|
||||
|
||||
url :
|
||||
|
||||
user:
|
||||
pass:
|
||||
17
.legacy/docs/index.md
Normal file
17
.legacy/docs/index.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Welcome to MkDocs
|
||||
|
||||
For full documentation visit [mkdocs.org](https://www.mkdocs.org).
|
||||
|
||||
## Commands
|
||||
|
||||
* `mkdocs new [dir-name]` - Create a new project.
|
||||
* `mkdocs serve` - Start the live-reloading docs server.
|
||||
* `mkdocs build` - Build the documentation site.
|
||||
* `mkdocs -h` - Print help message and exit.
|
||||
|
||||
## Project layout
|
||||
|
||||
mkdocs.yml # The configuration file.
|
||||
docs/
|
||||
index.md # The documentation homepage.
|
||||
... # Other markdown pages, images and other files.
|
||||
9
.legacy/docs/license.md
Normal file
9
.legacy/docs/license.md
Normal file
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
25
.legacy/docs/view.sql.md
Normal file
25
.legacy/docs/view.sql.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# the view for custom reporting
|
||||
|
||||
## Create the View
|
||||
|
||||
```
|
||||
|
||||
## Drop the view
|
||||
|
||||
DROP VIEW IF EXISTS report_twitchdata_top_1500_channels;
|
||||
|
||||
CREATE VIEW report_twitchdata_top_1500_channels AS
|
||||
SELECT
|
||||
`tag` "username",`url`,`logo` "logo_url", `all_time_peak_viewers`, `avg_viewers` "average_viewers", `followers_gained`, `hours_streamed`, `hours_watched`, `rank`, `total_followers`,
|
||||
CASE
|
||||
WHEN total_views = -1 THEN 'null'
|
||||
ELSE total_views
|
||||
END AS total_views
|
||||
from twitch_channel;
|
||||
|
||||
-- Select data from the view
|
||||
|
||||
SELECT * FROM report_twitchdata_top_1500_channels;
|
||||
|
||||
|
||||
```
|
||||
98
.legacy/gemini
Normal file
98
.legacy/gemini
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.example.filedownload.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "file_downloads")
|
||||
public class FileDownload {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String hostIp;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDateTime dateTime;
|
||||
|
||||
// Constructors, getters and setters
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
package com.example.filedownload.service;
|
||||
|
||||
import com.example.filedownload.model.FileDownload;
|
||||
import com.example.filedownload.repository.FileDownloadRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class FileDownloadService {
|
||||
|
||||
@Autowired
|
||||
private FileDownloadRepository fileDownloadRepository;
|
||||
|
||||
public FileDownload save(String url, String hostIp) {
|
||||
FileDownload fileDownload = new FileDownload();
|
||||
fileDownload.setUrl(url);
|
||||
fileDownload.setHostIp(hostIp);
|
||||
fileDownload.setDateTime(LocalDateTime.now());
|
||||
return fileDownloadRepository.save(fileDownload);
|
||||
}
|
||||
}
|
||||
|
||||
package com.example.filedownload.service;
|
||||
|
||||
import com.example.filedownload.model.FileDownload;
|
||||
import com.example.filedownload.repository.FileDownloadRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class FileDownloadService {
|
||||
|
||||
@Autowired
|
||||
private FileDownloadRepository fileDownloadRepository;
|
||||
|
||||
public FileDownload save(String url, String hostIp) {
|
||||
FileDownload fileDownload = new FileDownload();
|
||||
fileDownload.setUrl(url);
|
||||
fileDownload.setHostIp(hostIp);
|
||||
fileDownload.setDateTime(LocalDateTime.now());
|
||||
return fileDownloadRepository.save(fileDownload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package com.example.filedownload.controller;
|
||||
|
||||
import com.example.filedownload.model.FileDownload;
|
||||
import com.example.filedownload.service.FileDownloadService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class FileDownloadController {
|
||||
|
||||
@Autowired
|
||||
private FileDownloadService fileDownloadService;
|
||||
|
||||
@GetMapping("/doesexist/{url}")
|
||||
public boolean doesExist(@PathVariable String url) {
|
||||
String fullUrl = "google.com/" + url; // Assuming "google.com" is the base URL
|
||||
return fileDownloadService.existsByUrl(fullUrl);
|
||||
}
|
||||
}
|
||||
55
.legacy/nbactions.xml
Normal file
55
.legacy/nbactions.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<actions>
|
||||
<action>
|
||||
<actionName>run</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.vmArgs>-DDB_HOST=aventador.embanet.online -DDB_PORT=3306 -DDB_NAME=aventador -DDB_USER=aventador -DDB_PASS=aventador</exec.vmArgs>
|
||||
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
|
||||
<exec.appArgs></exec.appArgs>
|
||||
<exec.mainClass>edu.gsyoung.twitch.TwitchDataAcquisition</exec.mainClass>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>debug</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.vmArgs>-DDB_HOST=aventador.embanet.online -DDB_PORT=3306 -DDB_NAME=aventador -DDB_USER=aventador -DDB_PASS=aventador -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</exec.vmArgs>
|
||||
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
|
||||
<exec.appArgs></exec.appArgs>
|
||||
<exec.mainClass>edu.gsyoung.twitch.TwitchDataAcquisition</exec.mainClass>
|
||||
<exec.executable>java</exec.executable>
|
||||
<jpda.listen>true</jpda.listen>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>profile</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.vmArgs>-DDB_HOST=aventador.embanet.online -DDB_PORT=3306 -DDB_NAME=aventador -DDB_USER=aventador -DDB_PASS=aventador</exec.vmArgs>
|
||||
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
|
||||
<exec.mainClass>edu.gsyoung.twitch.TwitchDataAcquisition</exec.mainClass>
|
||||
<exec.executable>java</exec.executable>
|
||||
<exec.appArgs></exec.appArgs>
|
||||
</properties>
|
||||
</action>
|
||||
</actions>
|
||||
99
.legacy/pom.xml
Normal file
99
.legacy/pom.xml
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
|
||||
<version>3.1.0</version>
|
||||
|
||||
<relativePath/>
|
||||
|
||||
</parent>
|
||||
|
||||
<groupId>edu.gsyoung</groupId>
|
||||
|
||||
<artifactId>yankee-twitch-data-api</artifactId>
|
||||
|
||||
<name>yankee-twitch-data-api</name>
|
||||
|
||||
<description>yankee-twitch-data-api</description>
|
||||
|
||||
<version>1.0</version>
|
||||
|
||||
<properties>
|
||||
|
||||
<java.version>17</java.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.13.1</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
16
.legacy/readme.md
Normal file
16
.legacy/readme.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# twitch saas!
|
||||
|
||||
## sit rep
|
||||
|
||||
[DONE] the monthly stats data is loading but the repositories are all broken.
|
||||
|
||||
[NOW] now we need to enrich the html so that the js and the css load and properly render the page and render the table data
|
||||
|
||||
|
||||
## later
|
||||
|
||||
fix all the repos
|
||||
|
||||
create the click page for the phase one activities
|
||||
|
||||
add a menu to the click page
|
||||
49
.legacy/test/failure/eval-failure-check-exists.bash
Normal file
49
.legacy/test/failure/eval-failure-check-exists.bash
Normal file
@@ -0,0 +1,49 @@
|
||||
reset
|
||||
|
||||
clear
|
||||
|
||||
set -e
|
||||
|
||||
#set -x
|
||||
|
||||
##
|
||||
|
||||
echo
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo
|
||||
|
||||
##
|
||||
|
||||
curl -X GET http://localhost:8888/channel/monthly/games/failure/
|
||||
|
||||
sleep 4
|
||||
|
||||
echo
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo
|
||||
|
||||
curl -X GET \
|
||||
http://localhost:8888/channel/monthly/games/failure/exists \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://links.embanet.com/talisman.txt"
|
||||
}'
|
||||
|
||||
sleep 4
|
||||
|
||||
echo
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo
|
||||
|
||||
curl -X GET \
|
||||
http://localhost:8888/channel/monthly/games/failure/exists \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://www.garudanet.com/talisman.txt"
|
||||
}'
|
||||
24
.legacy/test/failure/eval-failure-create-new.bash
Normal file
24
.legacy/test/failure/eval-failure-create-new.bash
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
##
|
||||
|
||||
reset
|
||||
|
||||
clear
|
||||
|
||||
##
|
||||
|
||||
set -e
|
||||
|
||||
set -x
|
||||
|
||||
##
|
||||
|
||||
echo "##"
|
||||
echo "## creating new [failure] record in the database"
|
||||
echo "##"
|
||||
|
||||
curl -X POST \
|
||||
http://localhost:8888/channel/monthly/games/failure/add \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"url": "https://www.garudanet.com/talisman.txt","hostIP":"falcon"}'
|
||||
19
.legacy/test/success/eval-success-check-exists.bash
Normal file
19
.legacy/test/success/eval-success-check-exists.bash
Normal file
@@ -0,0 +1,19 @@
|
||||
echo "##"
|
||||
echo "##"
|
||||
echo "##"
|
||||
|
||||
curl -X GET https://osiris.yankee.valorantdigital.com/channel/monthly/games/success/
|
||||
|
||||
curl -X GET \
|
||||
https://osiris.yankee.valorantdigital.com/channel/monthly/games/success/exists \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://www.embanet.com/talisman.txt"
|
||||
}'
|
||||
|
||||
curl -X GET \
|
||||
https://osiris.yankee.valorantdigital.com/channel/monthly/games/success/exists \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://www.embanet.com/talisman.md"
|
||||
}'
|
||||
24
.legacy/test/success/eval-success-create-new.bash
Normal file
24
.legacy/test/success/eval-success-create-new.bash
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
##
|
||||
|
||||
reset
|
||||
|
||||
clear
|
||||
|
||||
##
|
||||
|
||||
set -e
|
||||
|
||||
set -x
|
||||
|
||||
##
|
||||
|
||||
echo "##"
|
||||
echo "## creating new [success] record in the database"
|
||||
echo "##"
|
||||
|
||||
curl -X POST \
|
||||
https://osiris.yankee.valorantdigital.com/channel/monthly/games/success/add \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"url": "https://www.embanet.com/talisman.txt","hostIP":"asdf"}'
|
||||
@@ -8,10 +8,10 @@ RUN mvn install -DskipTests
|
||||
|
||||
FROM eclipse-temurin:18-jre-alpine
|
||||
|
||||
COPY --from=mavenBuild /target/yankee-twitch-data-api-1.0.jar /yankee-twitch-data-api.jar
|
||||
COPY --from=mavenBuild /target/yankee-gnome-twitch-api-1.0.jar /yankee-gnome-twitch-api.jar
|
||||
|
||||
COPY --from=mavenBuild /src/main/resources/application.properties /application.properties
|
||||
|
||||
COPY --from=mavenBuild /src/main/resources/eighteen.stub.html /eighteen.stub.html
|
||||
|
||||
CMD ["java", "-jar", "/yankee-twitch-data-api.jar"]
|
||||
CMD ["java", "-jar", "/yankee-gnome-twitch-api.jar"]
|
||||
|
||||
3
compose.bash
Normal file → Executable file
3
compose.bash
Normal file → Executable file
@@ -18,13 +18,10 @@ echo
|
||||
echo "STARTED / yankee / twitchtracker / channel rankings"
|
||||
echo
|
||||
|
||||
|
||||
##
|
||||
|
||||
docker compose down --remove-orphans
|
||||
|
||||
#git pull
|
||||
|
||||
docker compose up --build -d
|
||||
|
||||
echo
|
||||
|
||||
191
compose.yaml
191
compose.yaml
@@ -1,143 +1,22 @@
|
||||
|
||||
services:
|
||||
|
||||
yankee-gnome-twitch-api:
|
||||
|
||||
##########################################
|
||||
##
|
||||
## aventador / network
|
||||
##
|
||||
##########################################
|
||||
|
||||
aventador-proxy:
|
||||
|
||||
container_name: aventador-proxy
|
||||
|
||||
image: nginxproxy/nginx-proxy:1.6
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
|
||||
- 80:80
|
||||
|
||||
- 443:443
|
||||
|
||||
volumes:
|
||||
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
|
||||
- /var/docker/nginx/html:/usr/share/nginx/html
|
||||
|
||||
- /var/docker/nginx/certs:/etc/nginx/certs
|
||||
|
||||
- /var/docker/nginx/vhost:/etc/nginx/vhost.d
|
||||
|
||||
logging:
|
||||
|
||||
options:
|
||||
|
||||
max-size: "10m"
|
||||
|
||||
max-file: "3"
|
||||
|
||||
aventador-letsencrypt:
|
||||
|
||||
container_name: aventador-letsencrypt
|
||||
|
||||
image: jrcs/letsencrypt-nginx-proxy-companion
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
volumes_from:
|
||||
|
||||
- aventador-proxy
|
||||
|
||||
volumes:
|
||||
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
- /var/docker/nginx/acme:/etc/acme.sh
|
||||
|
||||
environment:
|
||||
|
||||
DEFAULT_EMAIL: embanet@gmail.com
|
||||
|
||||
##
|
||||
## relational database server
|
||||
##
|
||||
## (vanilla mariadb w/ shinobi academy training db option)
|
||||
##
|
||||
|
||||
yankee-database-server:
|
||||
|
||||
container_name: yankee-database-server
|
||||
|
||||
image: softwareshinobi/shinobi-academy-database-server
|
||||
|
||||
ports:
|
||||
|
||||
- "3306:3306"
|
||||
|
||||
environment:
|
||||
|
||||
MYSQL_ROOT_PASSWORD: aggiepride
|
||||
|
||||
MYSQL_DATABASE: yankee
|
||||
|
||||
MYSQL_USER: yankee
|
||||
|
||||
MYSQL_PASSWORD: yankee
|
||||
|
||||
##
|
||||
## web assessible query tool sitting on top of the database server
|
||||
##
|
||||
yankee-database-query:
|
||||
|
||||
container_name: yankee-database-query
|
||||
|
||||
image: beeyev/phpmyadmin-lightweight
|
||||
|
||||
ports:
|
||||
|
||||
- "3380:80"
|
||||
|
||||
depends_on:
|
||||
|
||||
- yankee-database-server
|
||||
|
||||
links:
|
||||
|
||||
- yankee-database-server
|
||||
|
||||
environment:
|
||||
|
||||
PMA_HOST: yankee-database-server:3306
|
||||
|
||||
VIRTUAL_HOST: database.yankee.embanet.online
|
||||
|
||||
LETSENCRYPT_HOST: database.yankee.embanet.online
|
||||
|
||||
####
|
||||
|
||||
##
|
||||
## central computing for all yankee operations
|
||||
##
|
||||
|
||||
yankee-twitch-data-api:
|
||||
|
||||
container_name: yankee-twitch-data-api
|
||||
container_name: yankee-gnome-twitch-api
|
||||
|
||||
image: valorantdigital/yankee-twitch-data-api
|
||||
image: softwareshinobi/yankee-gnome-twitch-api
|
||||
|
||||
depends_on:
|
||||
build:
|
||||
|
||||
- yankee-database-server
|
||||
context: .
|
||||
|
||||
dockerfile: Dockerfile
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
|
||||
- 48888:8888
|
||||
- 8888:8888
|
||||
|
||||
environment:
|
||||
|
||||
@@ -156,3 +35,57 @@ services:
|
||||
VIRTUAL_HOST: apis.yankee.embanet.online
|
||||
|
||||
LETSENCRYPT_HOST: apis.yankee.embanet.online
|
||||
|
||||
##########################################
|
||||
##
|
||||
## veneno / relational data
|
||||
##
|
||||
##########################################
|
||||
|
||||
veneno-database:
|
||||
|
||||
container_name: veneno-database
|
||||
|
||||
image: mariadb:latest
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
|
||||
- "3306:3306"
|
||||
|
||||
environment:
|
||||
|
||||
MYSQL_ROOT_PASSWORD: aggiepride
|
||||
|
||||
MYSQL_DATABASE: yankee_gnome_twitch
|
||||
|
||||
MYSQL_USER: yankee_gnome_twitch
|
||||
|
||||
MYSQL_PASSWORD: yankee_gnome_twitch
|
||||
|
||||
volumes:
|
||||
|
||||
- /yankee/volumes/database:/var/lib/mysql
|
||||
|
||||
veneno-phpmyadmin:
|
||||
|
||||
container_name: veneno-phpmyadmin
|
||||
|
||||
image: beeyev/phpmyadmin-lightweight
|
||||
|
||||
depends_on:
|
||||
|
||||
- veneno-database
|
||||
|
||||
links:
|
||||
|
||||
- veneno-database
|
||||
|
||||
environment:
|
||||
|
||||
PMA_HOST: veneno-database
|
||||
|
||||
VIRTUAL_HOST: database.yankee.embanet.online
|
||||
|
||||
LETSENCRYPT_HOST: database.yankee.embanet.online
|
||||
|
||||
1892
database/aventador.sql
Normal file
1892
database/aventador.sql
Normal file
File diff suppressed because it is too large
Load Diff
27
notes/20x.md
Normal file
27
notes/20x.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 20x log
|
||||
|
||||
nov 20.
|
||||
|
||||
## 20x ~ 9.00a
|
||||
|
||||
the app is up
|
||||
|
||||
new bash script to test all endpoints
|
||||
|
||||
cleaned out the round two stuff that was bad
|
||||
|
||||
git work that needs to be reworked
|
||||
|
||||
## next
|
||||
|
||||
the stub is pulling 20 pages of stubbed data on demand after a truncate. NO PROD
|
||||
|
||||
the stub doesnt use the real stuff only the service
|
||||
|
||||
demo script tested and verified
|
||||
|
||||
prod script cloned and ready for execute
|
||||
|
||||
## 20x
|
||||
|
||||
[done] source code refactoring for a better code base
|
||||
417
notes/cenat.html
Normal file
417
notes/cenat.html
Normal file
File diff suppressed because one or more lines are too long
1
notes/mkdocs.yml
Normal file
1
notes/mkdocs.yml
Normal file
@@ -0,0 +1 @@
|
||||
site_name: My Docs
|
||||
49
notes/readme.md
Normal file
49
notes/readme.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# duplicator-x
|
||||
|
||||
## https://twitchtracker.com/channels/ranking?page=18
|
||||
|
||||
paginated twitch tracker url
|
||||
|
||||
## http://localhost:8888/twitch/load
|
||||
|
||||
goes to the demo file and loads all the records.
|
||||
|
||||
#############################3
|
||||
|
||||
## twitchtracker api stub
|
||||
|
||||
http://localhost:8888/channel/stub/18
|
||||
|
||||
the static twitch data export page
|
||||
|
||||
stubs out of a snapshot of the trackertracker page 18 data. returns pure but stubbed and static data
|
||||
|
||||
http://localhost:8888/channel/stub/utility/populate
|
||||
|
||||
####
|
||||
|
||||
|
||||
http://localhost:8888/channel
|
||||
|
||||
show all channels
|
||||
http://localhost:8888/channel/
|
||||
|
||||
http://localhost:8888/tracker/stub/18
|
||||
|
||||
## refactor ###########
|
||||
|
||||
### SEE STUB rankings DATA
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/stub/rankings
|
||||
|
||||
### LOAD 1000 stubs
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/stub/load/
|
||||
|
||||
loads 1000 records of stubbed twitchtracker.com/channels/ranking
|
||||
|
||||
### LOAD 50 stubs
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/stub/load/17
|
||||
|
||||
loads 50 records of stubbed twitchtracker.com/channels/ranking
|
||||
6
pom.xml
6
pom.xml
@@ -18,11 +18,11 @@
|
||||
|
||||
<groupId>edu.gsyoung</groupId>
|
||||
|
||||
<artifactId>yankee-twitch-data-api</artifactId>
|
||||
<artifactId>yankee-gnome-twitch-api</artifactId>
|
||||
|
||||
<name>yankee-twitch-data-api</name>
|
||||
<name>yankee-gnome-twitch-api</name>
|
||||
|
||||
<description>yankee-twitch-data-api</description>
|
||||
<description>yankee-gnome-twitch-api</description>
|
||||
|
||||
<version>1.0</version>
|
||||
|
||||
|
||||
19
src/main/java/edu/gsyoung/twitch/TwitchDataAcquisition.java
Executable file
19
src/main/java/edu/gsyoung/twitch/TwitchDataAcquisition.java
Executable file
@@ -0,0 +1,19 @@
|
||||
package edu.gsyoung.twitch;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TwitchDataAcquisition {
|
||||
|
||||
public static void main(final String[] commandLineArguments) {
|
||||
|
||||
System.out.println("##");
|
||||
System.out.println("## launch > yankee twitch data api");
|
||||
System.out.println("##");
|
||||
|
||||
SpringApplication.run(TwitchDataAcquisition.class, commandLineArguments);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package edu.gsyoung.twitch.data.channel.monthly;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Entity
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Table(name = "monthly_stats")
|
||||
public class TwitchMonthlyGameStats {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer year;
|
||||
|
||||
private Integer month;
|
||||
|
||||
private Integer createdMonthID;
|
||||
|
||||
private String createdMonthName;
|
||||
|
||||
private Integer createdYear;
|
||||
|
||||
private Integer followers;
|
||||
|
||||
private Integer views;
|
||||
|
||||
private String status;
|
||||
|
||||
private boolean mature;
|
||||
|
||||
private String language;
|
||||
|
||||
private String createdDate;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("TwitchMonthlyGameStats{");
|
||||
sb.append("id=").append(id);
|
||||
sb.append(", name=").append(name);
|
||||
sb.append(", year=").append(year);
|
||||
sb.append(", month=").append(month);
|
||||
sb.append(", createdMonthID=").append(createdMonthID);
|
||||
sb.append(", createdMonthName=").append(createdMonthName);
|
||||
sb.append(", createdYear=").append(createdYear);
|
||||
sb.append(", followers=").append(followers);
|
||||
sb.append(", views=").append(views);
|
||||
sb.append(", status=").append(status);
|
||||
sb.append(", mature=").append(mature);
|
||||
sb.append(", language=").append(language);
|
||||
sb.append(", createdDate=").append(createdDate);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(Integer year) {
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public Integer getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
public void setMonth(Integer month) {
|
||||
this.month = month;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getCreatedMonthID() {
|
||||
return createdMonthID;
|
||||
}
|
||||
|
||||
public void setMonthID(Integer createdMonthID) {
|
||||
this.createdMonthID = createdMonthID;
|
||||
}
|
||||
|
||||
public String getCreatedMonthName() {
|
||||
return createdMonthName;
|
||||
}
|
||||
|
||||
public void setMonthName(String createdMonthName) {
|
||||
this.createdMonthName = createdMonthName;
|
||||
}
|
||||
|
||||
public Integer getCreatedYear() {
|
||||
return createdYear;
|
||||
}
|
||||
|
||||
public void setCreatedYear(Integer createdYear) {
|
||||
this.createdYear = createdYear;
|
||||
}
|
||||
|
||||
public int getFollowers() {
|
||||
return followers;
|
||||
}
|
||||
|
||||
public void setFollowers(Integer followers) {
|
||||
this.followers = followers;
|
||||
}
|
||||
|
||||
public int getViews() {
|
||||
return views;
|
||||
}
|
||||
|
||||
public void setViews(Integer views) {
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isMature() {
|
||||
return mature;
|
||||
}
|
||||
|
||||
public void setMature(Boolean mature) {
|
||||
this.mature = mature;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public String getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(String createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package edu.gsyoung.twitch.data.channel.monthly;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("channel/games/monthly")
|
||||
public class TwitchMonthlyGameStatsController {
|
||||
|
||||
@Autowired
|
||||
private TwitchMonthlyGameStatsService twitchMonthlyGameStatsService;
|
||||
|
||||
@GetMapping("")
|
||||
public String root() {
|
||||
|
||||
return this.getClass().descriptorString();
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<TwitchMonthlyGameStats> findAll() throws IOException {
|
||||
|
||||
return this.twitchMonthlyGameStatsService.findAll();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package edu.gsyoung.twitch.data.channel.monthly;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface TwitchMonthlyGameStatsRepository extends JpaRepository<TwitchMonthlyGameStats, Integer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package edu.gsyoung.twitch.data.channel.monthly;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackOn = SQLException.class)
|
||||
public class TwitchMonthlyGameStatsService {
|
||||
|
||||
@Autowired
|
||||
public TwitchMonthlyGameStatsRepository repository;
|
||||
|
||||
public List<TwitchMonthlyGameStats> findAll() {
|
||||
|
||||
return this.repository.findAll();
|
||||
|
||||
}
|
||||
|
||||
public TwitchMonthlyGameStats save(TwitchMonthlyGameStats twitchChannel) {
|
||||
|
||||
return this.repository.save(twitchChannel);
|
||||
|
||||
}
|
||||
|
||||
public Boolean truncate() {
|
||||
|
||||
this.repository.deleteAllInBatch();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package edu.gsyoung.twitch.data.channel.rankings;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Entity
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Table(name = "channel_rankings")
|
||||
public class TwitchChannelRankings {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Integer id;
|
||||
|
||||
private String tag;
|
||||
|
||||
private String url;
|
||||
|
||||
private String logo;
|
||||
|
||||
private Integer rank;
|
||||
|
||||
private Integer avgViewers;
|
||||
|
||||
private Double hoursStreamed;
|
||||
|
||||
private Integer allTimePeakViewers;
|
||||
|
||||
private Integer hoursWatched;
|
||||
|
||||
private Integer followersGained;
|
||||
|
||||
private Integer totalFollowers;
|
||||
|
||||
private Long totalViews;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void setTag(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
public void setLogo(String logo) {
|
||||
this.logo = logo;
|
||||
}
|
||||
|
||||
public Integer getRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
public void setRank(Integer rank) {
|
||||
this.rank = rank;
|
||||
}
|
||||
|
||||
public Integer getAvgViewers() {
|
||||
return avgViewers;
|
||||
}
|
||||
|
||||
public void setAvgViewers(Integer avgViewers) {
|
||||
this.avgViewers = avgViewers;
|
||||
}
|
||||
|
||||
public Integer getAllTimePeakViewers() {
|
||||
return allTimePeakViewers;
|
||||
}
|
||||
|
||||
public void setAllTimePeakViewers(Integer allTimePeakViewers) {
|
||||
this.allTimePeakViewers = allTimePeakViewers;
|
||||
}
|
||||
|
||||
public Integer getHoursWatched() {
|
||||
return hoursWatched;
|
||||
}
|
||||
|
||||
public void setHoursWatched(Integer hoursWatched) {
|
||||
this.hoursWatched = hoursWatched;
|
||||
}
|
||||
|
||||
public Integer getFollowersGained() {
|
||||
return followersGained;
|
||||
}
|
||||
|
||||
public void setFollowersGained(Integer followersGained) {
|
||||
this.followersGained = followersGained;
|
||||
}
|
||||
|
||||
public Integer getTotalFollowers() {
|
||||
return totalFollowers;
|
||||
}
|
||||
|
||||
public void setTotalFollowers(Integer totalFollowers) {
|
||||
this.totalFollowers = totalFollowers;
|
||||
}
|
||||
|
||||
public Long getTotalViews() {
|
||||
return totalViews;
|
||||
}
|
||||
|
||||
public void setTotalViews(Long totalViews) {
|
||||
this.totalViews = totalViews;
|
||||
}
|
||||
|
||||
public Double getHoursStreamed() {
|
||||
return hoursStreamed;
|
||||
}
|
||||
|
||||
public void setHoursStreamed(Double hoursStreamed) {
|
||||
this.hoursStreamed = hoursStreamed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package edu.gsyoung.twitch.data.channel.rankings;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("channel/rankings")
|
||||
public class TwitchChannelRankingsController {
|
||||
|
||||
@Autowired
|
||||
private TwitchChannelRankingsService twitchChannelRankingsService;
|
||||
|
||||
@GetMapping("")
|
||||
public String root() {
|
||||
|
||||
return this.getClass().descriptorString();
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<TwitchChannelRankings> findAll() throws IOException {
|
||||
|
||||
return this.twitchChannelRankingsService.findAll();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package edu.gsyoung.twitch.data.channel.rankings;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface TwitchChannelRankingsRepository extends JpaRepository<TwitchChannelRankings, Integer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package edu.gsyoung.twitch.data.channel.rankings;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Service
|
||||
@Component
|
||||
@Transactional(rollbackOn = SQLException.class)
|
||||
public class TwitchChannelRankingsService {
|
||||
|
||||
@Autowired
|
||||
public TwitchChannelRankingsRepository repository;
|
||||
|
||||
// public TwitchChannelRankingsService(){
|
||||
//
|
||||
//// this.repository=new TwitchChannelRankingsRepository();
|
||||
//
|
||||
// }
|
||||
|
||||
public List<TwitchChannelRankings> findAll() {
|
||||
|
||||
return this.repository.findAll();
|
||||
|
||||
}
|
||||
|
||||
public TwitchChannelRankings save(TwitchChannelRankings twitchChannelRankings) {
|
||||
|
||||
return this.repository.save(twitchChannelRankings);
|
||||
|
||||
}
|
||||
|
||||
public Boolean truncate() {
|
||||
|
||||
this.repository.deleteAllInBatch();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//old
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.defunct;
|
||||
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStats;
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStatsService;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("sullygnome.com/channel/games/monthly")
|
||||
public class SullyGnomeMonthlyStatsController {
|
||||
|
||||
@Autowired
|
||||
private SullyGnomeMonthlyStatsService service;
|
||||
|
||||
@Autowired
|
||||
protected TwitchMonthlyGameStatsService monthly;
|
||||
|
||||
@GetMapping("load")
|
||||
public List<TwitchMonthlyGameStats> loadTwitchTrackerChannels()
|
||||
throws IOException {
|
||||
|
||||
return this.service.loadSullyGnomeMonthlyStats();
|
||||
|
||||
}
|
||||
|
||||
// @GetMapping("load/{pageNumber}")
|
||||
// public List<TwitchMonthlyGameStats> loadSingleSullyGnomePage(
|
||||
// @PathVariable final Integer pageNumber)
|
||||
// throws IOException {
|
||||
//
|
||||
// return this.service.loadSingleSullyGnomePage(pageNumber);
|
||||
//
|
||||
// }
|
||||
@GetMapping("truncate")
|
||||
public Boolean truncate() {
|
||||
|
||||
System.out.println("enter > truncate");
|
||||
|
||||
System.out.println(" > truncating database");
|
||||
|
||||
Boolean isSuccessfulTruncate = this.monthly.truncate();
|
||||
|
||||
System.out.println("returning / " + isSuccessfulTruncate);
|
||||
|
||||
System.out.println("exit < truncate");
|
||||
|
||||
return isSuccessfulTruncate;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.defunct;
|
||||
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStats;
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStatsService;
|
||||
import edu.gsyoung.twitch.data.channel.rankings.TwitchChannelRankingsService;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Component
|
||||
@Primary
|
||||
public class SullyGnomeMonthlyStatsService {
|
||||
|
||||
@Autowired
|
||||
public TwitchMonthlyGameStatsService gameStats;
|
||||
|
||||
@Autowired
|
||||
public TwitchChannelRankingsService rankings;
|
||||
|
||||
@Autowired
|
||||
public SullyGnomeMonthlyStatsUtility utility;
|
||||
|
||||
public final Integer NUMBER_CHANNELS_TO_PROCESS = 1500;
|
||||
|
||||
public final Integer DATA_LOAD_YEAR_BEGIN = 2022;
|
||||
|
||||
public final Integer DATA_LOAD_YEAR_END = 2024;
|
||||
|
||||
public final Integer DATA_LOAD_MONTH_BEGIN = 7;
|
||||
|
||||
public final Integer DATA_LOAD_MONTH_END = 10;
|
||||
|
||||
// public SullyGnomeMonthlyStatsService() {
|
||||
//
|
||||
// this.rankings = new TwitchChannelRankingsService();
|
||||
//
|
||||
// System.out.println("** SullyGnomeMonthlyStatsService SET UP! **");
|
||||
//
|
||||
// }
|
||||
|
||||
public final List<TwitchMonthlyGameStats> loadSullyGnomeMonthlyStats() throws IOException {
|
||||
|
||||
System.out.println("enter > service > loadSullyGnomeMonthlyStats");
|
||||
|
||||
final List<TwitchMonthlyGameStats> list = new ArrayList();
|
||||
|
||||
// final List<TwitchChannelRankings> channelRankingsList
|
||||
// = this.rankings.findAll();
|
||||
//for (final TwitchChannelRankings cyhannel : channelRankingsList) {
|
||||
final String channel = "redbull";
|
||||
|
||||
System.out.println("channel / " + channel);
|
||||
|
||||
for (Integer year = DATA_LOAD_YEAR_BEGIN; year <= DATA_LOAD_YEAR_END; year++) {
|
||||
|
||||
System.out.println("year / " + year);
|
||||
|
||||
for (Integer month = DATA_LOAD_MONTH_BEGIN; month <= DATA_LOAD_MONTH_END; month++) {
|
||||
|
||||
System.out.println("month / " + month);
|
||||
|
||||
String monthString = this.utility.convertMonthIDMonthName(month);
|
||||
|
||||
System.out.println("monthString / " + monthString);
|
||||
|
||||
System.out.println("now loading the loader for this unique month");
|
||||
|
||||
final List<TwitchMonthlyGameStats> gameStatList = this.loadSingleSullyGnomePage(channel, year, month);
|
||||
|
||||
System.out.println("result of unique month load: " + gameStatList);
|
||||
|
||||
list.addAll(gameStatList);
|
||||
|
||||
this.sleep();
|
||||
|
||||
}
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
System.out.println("enter < service < loadSullyGnomeMonthlyStats");
|
||||
// System.exit(80);
|
||||
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
public List<TwitchMonthlyGameStats> loadSingleSullyGnomePage(
|
||||
final String channel,
|
||||
final Integer year,
|
||||
final Integer month) {
|
||||
|
||||
System.out.println("enter > loadSingleSullyGnomePage");
|
||||
|
||||
System.out.println("channel / " + channel);
|
||||
System.out.println("year / " + year);
|
||||
System.out.println("month / " + month);
|
||||
|
||||
final String twitchTrackerPageHTML = this.fetchSinglePageHTMLSource(channel, year, month);
|
||||
|
||||
final List<TwitchMonthlyGameStats> loadedMonthlyGameStats
|
||||
= this.utility.convertHTMLSourceToRecordsList(
|
||||
twitchTrackerPageHTML
|
||||
);
|
||||
|
||||
for (TwitchMonthlyGameStats monthlyGameStat : loadedMonthlyGameStats) {
|
||||
|
||||
System.out.println("monthlyGameStat / " + monthlyGameStat);
|
||||
|
||||
this.gameStats.save(monthlyGameStat);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < loadSingleSullyGnomePage");
|
||||
|
||||
return loadedMonthlyGameStats;
|
||||
|
||||
}
|
||||
|
||||
public String fetchSinglePageHTMLSource(
|
||||
final String channel,
|
||||
final Integer year,
|
||||
final Integer month) {
|
||||
|
||||
return this.utility.fetchSinglePageHTMLSource(channel, year, month);
|
||||
|
||||
}
|
||||
|
||||
public void sleep() {
|
||||
|
||||
this.utility.sleep();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.defunct;
|
||||
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStats;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
public class SullyGnomeMonthlyStatsUtility {
|
||||
|
||||
protected String fetchSinglePageHTMLSource(
|
||||
final String channel,
|
||||
final Integer year,
|
||||
final Integer month) {
|
||||
|
||||
int pageNumber = -1;
|
||||
|
||||
System.out.println("enter > fetchSinglePageHTML(live)");
|
||||
|
||||
System.out.println("page / " + pageNumber);
|
||||
|
||||
String url = this.generateURL(channel, year, month);
|
||||
|
||||
System.out.println("url / " + url);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
String htmlContent = null;
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
HttpEntity.EMPTY,
|
||||
String.class);
|
||||
|
||||
if (response.getStatusCodeValue() == 200) {
|
||||
|
||||
htmlContent = response.getBody();
|
||||
|
||||
System.out.println("Retrieved HTML content:");
|
||||
|
||||
System.out.println(htmlContent);
|
||||
|
||||
} else {
|
||||
|
||||
System.out.println("Error: Unexpected status code: " + response.getStatusCodeValue());
|
||||
|
||||
}
|
||||
|
||||
System.out.println("htmlContent / " + htmlContent);
|
||||
|
||||
System.out.println("exit < fetchSinglePageHTML(live)");
|
||||
|
||||
return htmlContent;
|
||||
|
||||
}
|
||||
|
||||
protected String generateURL(
|
||||
final String channel,
|
||||
final Integer year,
|
||||
final Integer month) {
|
||||
|
||||
final String url = "https://sullygnome.com/channel/" + channel + "/"
|
||||
+ year + this.convertMonthIDMonthName(month) + "/games";
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
protected String convertMonthIDMonthName(final Integer monthNumber) {
|
||||
|
||||
Map<String, Integer> monthMap = new HashMap<>();
|
||||
|
||||
String monthString = "";
|
||||
|
||||
monthString = switch (monthNumber) {
|
||||
case 1 ->
|
||||
"january";
|
||||
case 2 ->
|
||||
"february";
|
||||
case 3 ->
|
||||
"march";
|
||||
case 4 ->
|
||||
"april";
|
||||
case 5 ->
|
||||
"may";
|
||||
case 6 ->
|
||||
"june";
|
||||
case 7 ->
|
||||
"july";
|
||||
case 8 ->
|
||||
"august";
|
||||
case 9 ->
|
||||
"september";
|
||||
case 10 ->
|
||||
"october";
|
||||
case 11 ->
|
||||
"november";
|
||||
case 12 ->
|
||||
"december";
|
||||
default ->
|
||||
"ERRORRR";
|
||||
};
|
||||
|
||||
return monthString;
|
||||
|
||||
}
|
||||
|
||||
protected Integer getMonthNumber(String monthString) {
|
||||
|
||||
Map<String, Integer> monthMap = new HashMap<>();
|
||||
|
||||
monthMap.put("January", 1);
|
||||
monthMap.put("February", 2);
|
||||
monthMap.put("March", 3);
|
||||
monthMap.put("April", 4);
|
||||
monthMap.put("May", 5);
|
||||
monthMap.put("June", 6);
|
||||
monthMap.put("July", 7);
|
||||
monthMap.put("August", 8);
|
||||
monthMap.put("September", 9);
|
||||
monthMap.put("October", 10);
|
||||
monthMap.put("November", 11);
|
||||
monthMap.put("December", 12);
|
||||
|
||||
return monthMap.getOrDefault(monthString, 0);
|
||||
|
||||
}
|
||||
|
||||
protected List<TwitchMonthlyGameStats> convertHTMLSourceToRecordsList(final String html) {
|
||||
|
||||
final TwitchMonthlyGameStats twitchMonthlyGameStats = new TwitchMonthlyGameStats();
|
||||
|
||||
// final TwitchThingTwo twitchChannels = new TwitchThingTwo();
|
||||
final Document document = Jsoup.parse(html);
|
||||
|
||||
////////////////////
|
||||
Elements elements = document.select("span.PageHeaderMiddleWithImageHeaderP2");
|
||||
|
||||
for (Element element : elements) {
|
||||
String text = element.text();
|
||||
String[] parts = text.split(" ");
|
||||
|
||||
// Assuming the format is "Games played in Month Year"
|
||||
String monthString = parts[3];
|
||||
int year = Integer.parseInt(parts[4]);
|
||||
|
||||
// Get the month number (1-based)
|
||||
int month = this.getMonthNumber(monthString);
|
||||
//int month = -1;
|
||||
|
||||
// Create the ID
|
||||
// int id = year * 100 + month;
|
||||
System.out.println("Month (str): " + monthString);
|
||||
|
||||
System.out.println("Month: " + month);
|
||||
|
||||
twitchMonthlyGameStats.setMonth(month);
|
||||
|
||||
System.out.println("Year: " + year);
|
||||
|
||||
twitchMonthlyGameStats.setYear(year);
|
||||
|
||||
// System.out.println("ID: " + id);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
final Elements tableRows = document.select(".MiddleSubHeaderItem");
|
||||
|
||||
Elements values = document.select(".MiddleSubHeaderItemValue");
|
||||
|
||||
Elements titleElements = document.select("title");
|
||||
|
||||
// Extract the channel name (assuming it's the first part before the hyphen)
|
||||
String channelName = titleElements.text().split("-")[0].trim();
|
||||
|
||||
System.out.println("Channel Name: " + channelName);
|
||||
|
||||
twitchMonthlyGameStats.setName(channelName);
|
||||
|
||||
for (int i = 0; i < tableRows.size(); i++) {
|
||||
|
||||
Element item = tableRows.get(i);
|
||||
|
||||
Element value = values.get(i);
|
||||
|
||||
String text = item.text();
|
||||
|
||||
String valueText = value.text();
|
||||
|
||||
switch (text) {
|
||||
|
||||
case "Followers:" ->
|
||||
twitchMonthlyGameStats.setFollowers(Integer.parseInt(valueText.replace(",", "")));
|
||||
|
||||
case "Views:" ->
|
||||
twitchMonthlyGameStats.setViews(Integer.parseInt(valueText.replace(",", "")));
|
||||
|
||||
case "Status:" ->
|
||||
twitchMonthlyGameStats.setStatus(valueText);
|
||||
|
||||
case "Mature:" ->
|
||||
twitchMonthlyGameStats.setMature(valueText.equals("Yes"));
|
||||
|
||||
case "Language:" ->
|
||||
twitchMonthlyGameStats.setLanguage(valueText);
|
||||
|
||||
case "Created:" ->
|
||||
twitchMonthlyGameStats.setCreatedDate(valueText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////
|
||||
// Define a formatter to parse the given date format
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd'th' MMM yyyy", Locale.ENGLISH);
|
||||
|
||||
try {
|
||||
|
||||
LocalDate date = LocalDate.parse(twitchMonthlyGameStats.getCreatedDate(), formatter);
|
||||
|
||||
// Extract the desired values
|
||||
int monthId = date.getMonthValue();
|
||||
|
||||
int year = date.getYear();
|
||||
|
||||
String monthStr = date.getMonth().toString().toLowerCase();
|
||||
|
||||
System.out.println("Month ID: " + monthId);
|
||||
|
||||
twitchMonthlyGameStats.setMonthID(monthId);
|
||||
|
||||
System.out.println("Year: " + year);
|
||||
|
||||
twitchMonthlyGameStats.setCreatedYear(year);
|
||||
|
||||
System.out.println("Month String: " + monthStr);
|
||||
|
||||
twitchMonthlyGameStats.setMonthName(monthStr);
|
||||
|
||||
} catch (DateTimeParseException e) {
|
||||
|
||||
System.err.println("Invalid date format: " + e.getMessage());
|
||||
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
System.out.println("output / channelInfo / " + twitchMonthlyGameStats);
|
||||
// for (Element tableRow : tableRows) {
|
||||
//
|
||||
// Elements elements = tableRow.select("td");
|
||||
//
|
||||
// System.out.println("elements / " + elements);
|
||||
//
|
||||
// TwitchChannel twitchChannel = this.convertTwitchDataElementsToTwitchChannel(elements);
|
||||
//
|
||||
// System.out.println("parsed twitchChannel / " + twitchChannel);
|
||||
//
|
||||
// if (twitchChannel != null) {
|
||||
//
|
||||
// twitchChannels.add(twitchChannel);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
List<TwitchMonthlyGameStats> asdf = new ArrayList();
|
||||
|
||||
asdf.add(twitchMonthlyGameStats);
|
||||
|
||||
return asdf;
|
||||
|
||||
}
|
||||
|
||||
protected void sleep() {
|
||||
|
||||
System.out.println("enter > sleep function");
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
int randomSleepTime = random.nextInt(91) + 90;
|
||||
|
||||
System.out.println("Sleeping for " + randomSleepTime + " seconds");
|
||||
|
||||
try {
|
||||
|
||||
TimeUnit.SECONDS.sleep(randomSleepTime);
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
|
||||
Logger.getLogger(SullyGnomeMonthlyStatsUtility.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < sleep function");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.defunct.stub;
|
||||
|
||||
import edu.gsyoung.twitch.data.channel.monthly.TwitchMonthlyGameStats;
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.defunct.SullyGnomeMonthlyStatsController;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("sullygnome.com/stub/channel/games/monthly")
|
||||
public class SullyGnomeMonthlyStatsStubController extends SullyGnomeMonthlyStatsController {
|
||||
|
||||
@Autowired
|
||||
public SullyGnomeMonthlyStatsStubService stubservice;
|
||||
|
||||
// public SullyGnomeMonthlyStatsStubController() {
|
||||
//
|
||||
// System.out.println("enter > constructor");
|
||||
//
|
||||
// this.service2 = new SullyGnomeMonthlyStatsStubService();
|
||||
//
|
||||
// System.out.println("this.twitchTrackerChannelService / " + this.service2);
|
||||
//
|
||||
// System.out.println("exit < constructor");
|
||||
//
|
||||
// }
|
||||
|
||||
@GetMapping("")
|
||||
public String root() throws IOException {
|
||||
|
||||
return this.getClass().getName();
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("load")
|
||||
@Override
|
||||
public final List<TwitchMonthlyGameStats> loadTwitchTrackerChannels()
|
||||
throws IOException {
|
||||
|
||||
return this.stubservice.loadSullyGnomeMonthlyStats();
|
||||
|
||||
}
|
||||
|
||||
// @GetMapping("load/{pageNumber}")
|
||||
// public List<TwitchMonthlyGameStats> loadSingleSullyGnomePage(
|
||||
// @PathVariable final Integer pageNumber)
|
||||
// throws IOException {
|
||||
//
|
||||
// return this.service.loadSingleSullyGnomePage(pageNumber);
|
||||
//
|
||||
// }
|
||||
@GetMapping("truncate")
|
||||
public Boolean truncate() {
|
||||
|
||||
System.out.println("enter > truncate");
|
||||
|
||||
System.out.println(" > truncating database");
|
||||
|
||||
Boolean isSuccessfulTruncate = this.monthly.truncate();
|
||||
|
||||
System.out.println("returning / " + isSuccessfulTruncate);
|
||||
|
||||
System.out.println("exit < truncate");
|
||||
|
||||
return isSuccessfulTruncate;
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("html")
|
||||
public String getStubHTML() throws IOException {
|
||||
|
||||
System.out.println("enter > display stubbed 50x single twitchtracker.com channel rankings");
|
||||
|
||||
String twitchTrackerPageHTML = this.stubservice.fetchSinglePageHTMLSource("", -1, -1);
|
||||
|
||||
System.out.println("yo / " + twitchTrackerPageHTML);
|
||||
|
||||
System.out.println("exit < display stubbed 50x single twitchtracker.com channel rankings");
|
||||
|
||||
return twitchTrackerPageHTML;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.defunct.stub;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.defunct.SullyGnomeMonthlyStatsService;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SullyGnomeMonthlyStatsStubService extends SullyGnomeMonthlyStatsService {
|
||||
|
||||
@Override
|
||||
public String fetchSinglePageHTMLSource(
|
||||
final String channel,
|
||||
final Integer year,
|
||||
final Integer month) {
|
||||
|
||||
System.out.println("enter > fetchSinglePageHTMLSource(STUB)");
|
||||
|
||||
try {
|
||||
|
||||
ClassPathResource resource = new ClassPathResource("kaicenat-2022january.stub.html");
|
||||
|
||||
String content = Files.readString(Paths.get(resource.getURI()), StandardCharsets.UTF_8);
|
||||
|
||||
return this.massage(ResponseEntity.ok(content).getBody());
|
||||
|
||||
} catch (IOException ex) {
|
||||
|
||||
Logger.getLogger(SullyGnomeMonthlyStatsStubService.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit > fetchSinglePageHTMLSource(STUB)");
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sleep() {
|
||||
|
||||
System.out.println("enter > sleep function (STUB)");
|
||||
|
||||
System.out.println("exit < sleep function (STUB)");
|
||||
|
||||
}
|
||||
|
||||
private String massage(String body) {
|
||||
|
||||
body = body.replaceAll("href=\"/", "href=\"https://sullygnome.com/");
|
||||
|
||||
body = body.replaceAll("src=\"/", "src=\"https://sullygnome.com/");
|
||||
|
||||
System.out.println("body / !!!!");
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.failure;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sully_download_failure")
|
||||
public class SullyDownloadFailure {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String hostIP;
|
||||
|
||||
public Long getId() {
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
|
||||
this.id = id;
|
||||
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
|
||||
this.url = url;
|
||||
|
||||
}
|
||||
|
||||
public String getHostIP() {
|
||||
|
||||
return hostIP;
|
||||
|
||||
}
|
||||
|
||||
public void setHostIP(String hostIP) {
|
||||
|
||||
this.hostIP = hostIP;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("SullyDownloadFailure{");
|
||||
|
||||
stringBuilder.append("id=").append(id);
|
||||
|
||||
stringBuilder.append(", url=").append(url);
|
||||
|
||||
stringBuilder.append(", hostIp=").append(hostIP);
|
||||
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.failure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("channel/monthly/games/failure")
|
||||
public class SullyDownloadFailureController {
|
||||
|
||||
@Autowired
|
||||
private SullyDownloadFailureService sullyDownloadFailureService;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<SullyDownloadFailure> findAll() {
|
||||
|
||||
return this.sullyDownloadFailureService.findAll();
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("add")
|
||||
public SullyDownloadFailure addSullyDownloadFailure(@RequestBody SullyDownloadFailure sullyDownloadFailure) {
|
||||
|
||||
System.out.println("enter > addSullyDownloadFailure");
|
||||
|
||||
System.out.println("sullyDownloadFailure / " + sullyDownloadFailure);
|
||||
|
||||
return this.sullyDownloadFailureService.save(sullyDownloadFailure);
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("exists")
|
||||
public Boolean exists(@RequestBody Map map) {
|
||||
|
||||
System.out.println("enter > exists");
|
||||
|
||||
System.out.println("param -> map / " + map);
|
||||
|
||||
String url = (String) map.get("url");
|
||||
|
||||
System.out.println("full - url - " + url);
|
||||
|
||||
Boolean exists = sullyDownloadFailureService.existsByUrl(url);
|
||||
|
||||
System.out.println("exists / " + exists);
|
||||
|
||||
return exists;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.failure;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SullyDownloadFailureRepository extends JpaRepository<SullyDownloadFailure, Long> {
|
||||
|
||||
boolean existsByUrl(String url);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.failure;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SullyDownloadFailureService {
|
||||
|
||||
@Autowired
|
||||
private SullyDownloadFailureRepository sullyDownloadFailureRepository;
|
||||
|
||||
public List<SullyDownloadFailure> findAll() {
|
||||
|
||||
return this.sullyDownloadFailureRepository.findAll();
|
||||
|
||||
}
|
||||
|
||||
public SullyDownloadFailure save(final SullyDownloadFailure sullyDownloadFailure) {
|
||||
|
||||
return this.sullyDownloadFailureRepository.save(sullyDownloadFailure);
|
||||
|
||||
}
|
||||
|
||||
public boolean existsByUrl(final String url) {
|
||||
|
||||
return this.sullyDownloadFailureRepository.existsByUrl(url);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.success;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sully_download_success")
|
||||
public class SullyDownloadSuccess {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String hostIP;
|
||||
|
||||
public Long getId() {
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
|
||||
this.id = id;
|
||||
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
|
||||
this.url = url;
|
||||
|
||||
}
|
||||
|
||||
public String getHostIP() {
|
||||
|
||||
return hostIP;
|
||||
|
||||
}
|
||||
|
||||
public void setHostIP(String hostIP) {
|
||||
|
||||
this.hostIP = hostIP;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.append("SullyDownloadSuccess{");
|
||||
|
||||
stringBuilder.append("id=").append(id);
|
||||
|
||||
stringBuilder.append(", url=").append(url);
|
||||
|
||||
stringBuilder.append(", hostIp=").append(hostIP);
|
||||
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.success;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.download.success.SullyDownloadSuccess;
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.download.failure.SullyDownloadFailureService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("channel/monthly/games/success")
|
||||
public class SullyDownloadSuccessController {
|
||||
|
||||
@Autowired
|
||||
private SullyDownloadSuccessService sullyDownloadSuccessService;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<SullyDownloadSuccess> findAll() {
|
||||
|
||||
return this.sullyDownloadSuccessService.findAll();
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("add")
|
||||
public SullyDownloadSuccess addSullyDownloadSuccess(@RequestBody SullyDownloadSuccess sullyDownloadSuccess) {
|
||||
|
||||
System.out.println("enter > addSullyDownloadSuccess");
|
||||
|
||||
System.out.println("sullyDownloadSuccess / " + sullyDownloadSuccess);
|
||||
|
||||
return this.sullyDownloadSuccessService.save(sullyDownloadSuccess);
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("exists")
|
||||
public Boolean exists(@RequestBody Map map) {
|
||||
|
||||
System.out.println("enter > exists");
|
||||
|
||||
System.out.println("param -> map / " + map);
|
||||
|
||||
String url = (String) map.get("url");
|
||||
|
||||
System.out.println("full - url - " + url);
|
||||
|
||||
Boolean exists = sullyDownloadSuccessService.existsByUrl(url);
|
||||
|
||||
System.out.println("exists / " + exists);
|
||||
|
||||
return exists;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.success;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SullyDownloadSuccessRepository extends JpaRepository<SullyDownloadSuccess, Long> {
|
||||
|
||||
boolean existsByUrl(String url);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.download.success;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SullyDownloadSuccessService {
|
||||
|
||||
@Autowired
|
||||
private SullyDownloadSuccessRepository sullyDownloadSuccessRepository;
|
||||
|
||||
public List<SullyDownloadSuccess> findAll() {
|
||||
|
||||
return this.sullyDownloadSuccessRepository.findAll();
|
||||
|
||||
}
|
||||
|
||||
public SullyDownloadSuccess save(final SullyDownloadSuccess sullyDownloadSuccess) {
|
||||
|
||||
return this.sullyDownloadSuccessRepository.save(sullyDownloadSuccess);
|
||||
|
||||
}
|
||||
|
||||
public boolean existsByUrl(final String url) {
|
||||
|
||||
return this.sullyDownloadSuccessRepository.existsByUrl(url);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.games;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author shinobi
|
||||
*/
|
||||
public class Game {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.games;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
public class Parser {
|
||||
|
||||
protected static Element findTargetBox(final Document document, String f1, String f2) {
|
||||
|
||||
final Elements matchingElements = document.select("div.InfoStatPanelOuter");
|
||||
|
||||
Element match = null;
|
||||
|
||||
for (final Element element : matchingElements) {
|
||||
|
||||
final String title = element.attr("title");
|
||||
|
||||
if (title.toLowerCase().contains(f1) && title.toLowerCase().contains(f2)) {
|
||||
|
||||
// final Element secondBoxGroup = element.select("div.InfoStatPanelTLCell").first();
|
||||
match = element;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("match / " + match);
|
||||
|
||||
return match;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> one(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "watching", "total time");
|
||||
|
||||
System.out.println("inner / " + match.child(0).child(1));
|
||||
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("(1) / watching total time / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(1) / total time / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("(1) / total time / 2 / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(1) / total time / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("(1) / total time 3 // " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(1) / total time / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(1) / total time / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> two(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "broadcasting", "total time");
|
||||
|
||||
System.out.println("inner / " + match.child(0).child(1));
|
||||
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("(2) / total time / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(2) / total time / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("(2) / total time / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(2) / total time / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("(2) / total time / " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(2) / total time / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(2) / total time / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> three(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "watching", "average people");
|
||||
|
||||
System.out.println("inner / " + match.child(0).child(1));
|
||||
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("(3) / average people / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(3) / average people / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("(3) / average people / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(3) / average people / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("(3) / average people / " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(3) / average people / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(3) / average people / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> four(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "stream", "average channels");
|
||||
|
||||
System.out.println("inner / " + match.child(0).child(1));
|
||||
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("(4) / average viewers / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(4) / average viewers / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("(4) / average viewers / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(4) / average viewers / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("(4) / average viewers / " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(4) / average viewers / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(4) / average viewers / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> five(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "average viewers", "channel");
|
||||
|
||||
// System.out.println("inner / " + match.child(0).child(1));
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("val1 / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(5) / average viewers / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("val2 / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(5) / average viewers / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("iter 3: " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(5) / average viewers / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(5) / average viewers / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> six(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "watch", "peak viewers");
|
||||
|
||||
// System.out.println("inner / " + match.child(0).child(1));
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("val1 / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(6) / peak viewers / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("val2 / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(6) / peak viewers / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("iter 3: " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(6) / peak viewers / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(6) / peak viewers / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
public static Map<String, Number> seven(final Document document) {
|
||||
|
||||
final Map<String, Number> dataMap = new HashMap<>();
|
||||
|
||||
Element match = findTargetBox(document, "stream", "total channels");
|
||||
|
||||
System.out.println("inner / " + match.child(0).child(1));
|
||||
|
||||
////////
|
||||
System.out.println("value 1 / " + match.child(0).child(1).text());
|
||||
|
||||
String original = match.child(0).child(1).text();
|
||||
|
||||
String cleaned = original.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount = Double.valueOf(cleaned);
|
||||
|
||||
System.out.println("(7) / total channels / " + hoursGrowthAmount);
|
||||
|
||||
dataMap.put("(7) / total channels / 111", hoursGrowthAmount);
|
||||
|
||||
////////
|
||||
System.out.println("value 2 / " + match.child(0).child(2).text());
|
||||
|
||||
String original2 = match.child(0).child(2).text();
|
||||
|
||||
String cleaned2 = original2.replace(",", "");
|
||||
|
||||
final Double hoursGrowthAmount2 = Double.valueOf(cleaned2);
|
||||
|
||||
System.out.println("(7) / total channels / 2 / " + hoursGrowthAmount2);
|
||||
|
||||
dataMap.put("(7) / total channels / 222", hoursGrowthAmount2);
|
||||
|
||||
////////
|
||||
System.out.println("value 3 / " + match.child(0).child(3).text());
|
||||
|
||||
String original3 = match.child(0).child(3).text();
|
||||
|
||||
String cleaned3 = original3.replace(",", "").replaceAll("\\%", "");
|
||||
|
||||
final Double hoursGrowthAmount3 = Double.valueOf(cleaned3);
|
||||
|
||||
System.out.println("(7) / total channels / 3 / " + hoursGrowthAmount3);
|
||||
|
||||
dataMap.put("(7) / total channels / 333", hoursGrowthAmount3);
|
||||
|
||||
////////
|
||||
System.out.println("(7) / total channels / map / " + dataMap);
|
||||
|
||||
return dataMap;
|
||||
|
||||
}
|
||||
|
||||
private static Map dowrk(Element elements) {
|
||||
return null;
|
||||
// System.out.println("yo!");
|
||||
//
|
||||
// final Map<String, Long> dataMap = new HashMap<>();
|
||||
//
|
||||
// String totalTimeWatchedStr = elements.first().text();
|
||||
//
|
||||
// totalTimeWatchedStr = totalTimeWatchedStr.replace(",", "");
|
||||
//
|
||||
// Long totalHoursWatched = Long.parseLong(totalTimeWatchedStr);
|
||||
//
|
||||
// System.out.println("hoursWatched: " + totalHoursWatched);
|
||||
//
|
||||
//
|
||||
// Element totalTimeElement = element.child(0).child(1);
|
||||
//
|
||||
// System.out.println("look here for only a single / " + totalTimeElement);
|
||||
//
|
||||
// if (totalTimeElement != null) {
|
||||
//
|
||||
// String totalTimeStr = totalTimeElement.text().replace(",", "");
|
||||
//
|
||||
// dataMap.put("Total Time Broadcast", Long.valueOf(totalTimeStr));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// // Extract Time Difference
|
||||
// Element timeDifferenceElement = element.child(1);
|
||||
// if (timeDifferenceElement != null) {
|
||||
// String timeDifferenceStr = timeDifferenceElement.text().replace("+", "").replace(",", "");
|
||||
// dataMap.put("Time Difference", Long.valueOf(timeDifferenceStr));
|
||||
// }
|
||||
//
|
||||
// // Extract Time Change Percentage
|
||||
// Element timeChangeElement = element.child(2);
|
||||
//
|
||||
// if (timeChangeElement != null) {
|
||||
//
|
||||
// String timeChangeStr = totalTimeElement.text().replace("%", "");
|
||||
//
|
||||
// dataMap.put("Time Change Percentage", Long.valueOf(timeChangeStr));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// System.out.println("dataMap updated / " + dataMap);
|
||||
//
|
||||
// return new HashMap();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.games;
|
||||
|
||||
import edu.gsyoung.twitch.data.channel.monthly.*;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Entity
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Table(name = "SullyGnomeGame")
|
||||
public class SullyGnomeGame {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
//##
|
||||
private Integer year;
|
||||
|
||||
private Integer month;
|
||||
|
||||
private Integer createdMonthID;
|
||||
|
||||
private String createdMonthName;
|
||||
|
||||
private Integer createdYear;
|
||||
|
||||
private Integer followers;
|
||||
|
||||
private Integer views;
|
||||
|
||||
private String status;
|
||||
|
||||
private boolean mature;
|
||||
|
||||
private String language;
|
||||
|
||||
private String createdDate;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("TwitchMonthlyGameStats{");
|
||||
sb.append("id=").append(id);
|
||||
sb.append(", name=").append(name);
|
||||
sb.append(", year=").append(year);
|
||||
sb.append(", month=").append(month);
|
||||
sb.append(", createdMonthID=").append(createdMonthID);
|
||||
sb.append(", createdMonthName=").append(createdMonthName);
|
||||
sb.append(", createdYear=").append(createdYear);
|
||||
sb.append(", followers=").append(followers);
|
||||
sb.append(", views=").append(views);
|
||||
sb.append(", status=").append(status);
|
||||
sb.append(", mature=").append(mature);
|
||||
sb.append(", language=").append(language);
|
||||
sb.append(", createdDate=").append(createdDate);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(Integer year) {
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public Integer getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
public void setMonth(Integer month) {
|
||||
this.month = month;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getCreatedMonthID() {
|
||||
return createdMonthID;
|
||||
}
|
||||
|
||||
public void setMonthID(Integer createdMonthID) {
|
||||
this.createdMonthID = createdMonthID;
|
||||
}
|
||||
|
||||
public String getCreatedMonthName() {
|
||||
return createdMonthName;
|
||||
}
|
||||
|
||||
public void setMonthName(String createdMonthName) {
|
||||
this.createdMonthName = createdMonthName;
|
||||
}
|
||||
|
||||
public Integer getCreatedYear() {
|
||||
return createdYear;
|
||||
}
|
||||
|
||||
public void setCreatedYear(Integer createdYear) {
|
||||
this.createdYear = createdYear;
|
||||
}
|
||||
|
||||
public int getFollowers() {
|
||||
return followers;
|
||||
}
|
||||
|
||||
public void setFollowers(Integer followers) {
|
||||
this.followers = followers;
|
||||
}
|
||||
|
||||
public int getViews() {
|
||||
return views;
|
||||
}
|
||||
|
||||
public void setViews(Integer views) {
|
||||
this.views = views;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isMature() {
|
||||
return mature;
|
||||
}
|
||||
|
||||
public void setMature(Boolean mature) {
|
||||
this.mature = mature;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public String getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(String createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.games;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("sullygnome.com/games")
|
||||
public class SullyGnomeGamesController {
|
||||
|
||||
protected SullyGnomeGamesService service = new SullyGnomeGamesService();
|
||||
|
||||
// protected TwitchChannelRankingsService rankings = new TwitchChannelRankingsService();
|
||||
// @GetMapping("load")
|
||||
// public final List<TwitchChannelRankings> loadSingleSullyGnomeGameFromURL()
|
||||
// throws IOException {
|
||||
//
|
||||
// return this.service.loadSingleSullyGnomeGameFromURL();
|
||||
//
|
||||
// }
|
||||
@GetMapping("")
|
||||
public String landing() {
|
||||
|
||||
return "what it do";
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("load/gta5")
|
||||
public Map loadSingleSullyGnomeGameFromURL()
|
||||
throws IOException {
|
||||
|
||||
return this.service.loadSingleSullyGnomeGameFromURL(
|
||||
"https://sullygnome.com/game/Grand_Theft_Auto_V/2023january");
|
||||
|
||||
}
|
||||
|
||||
// @GetMapping("truncate")
|
||||
// public Boolean truncate() {
|
||||
//
|
||||
// System.out.println("enter > truncate");
|
||||
//
|
||||
// System.out.println(" > truncating database");
|
||||
//
|
||||
// System.out.println("exit < truncate");
|
||||
//
|
||||
// return this.rankings.truncate();
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package edu.gsyoung.twitch.upstream.sullygnome.games;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
public class SullyGnomeGamesService {
|
||||
|
||||
public String fetchHTMLSourceFromURL(final String pageURL) {
|
||||
|
||||
System.out.println("enter > loadSingleSullyGnomeGameFromURL(live)");
|
||||
|
||||
System.out.println("page / " + pageURL);
|
||||
|
||||
String url = pageURL;
|
||||
|
||||
System.out.println("url / " + url);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
String htmlContent = null;
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
HttpEntity.EMPTY,
|
||||
String.class);
|
||||
|
||||
if (response.getStatusCodeValue() == 200) {
|
||||
|
||||
htmlContent = response.getBody();
|
||||
|
||||
System.out.println("Retrieved HTML content:");
|
||||
|
||||
System.out.println(htmlContent);
|
||||
|
||||
} else {
|
||||
|
||||
System.out.println("Error: Unexpected status code: " + response.getStatusCodeValue());
|
||||
|
||||
}
|
||||
|
||||
System.out.println("htmlContent / " + htmlContent);
|
||||
|
||||
System.out.println("exit < fetchSinglePageHTML(live)");
|
||||
|
||||
return htmlContent;
|
||||
|
||||
}
|
||||
|
||||
public Map loadSingleSullyGnomeGameFromURL(
|
||||
final String pageURL)
|
||||
throws IOException {
|
||||
|
||||
System.out.println("enter > loadSingleSullyGnomeGameFromURL()");
|
||||
|
||||
System.out.println("pageURL / " + pageURL);
|
||||
|
||||
// System.out.println("this.twitchTrackerChannelService / " + this.twitchTrackerChannelService);
|
||||
final String html = this.fetchHTMLSourceFromURL(pageURL);
|
||||
|
||||
System.out.println("html / " + html);
|
||||
|
||||
System.out.println("exiting");
|
||||
|
||||
final Map map = this.convertHTMLSourceToRecordsList(html);
|
||||
|
||||
System.out.println("loadedTwitchChannels / " + map);
|
||||
|
||||
for (Object loadedTwitchChannel : map.keySet()) {
|
||||
|
||||
System.out.println("element / " + loadedTwitchChannel);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < loadSingleSullyGnomeGameFromURL()");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected Map convertHTMLSourceToRecordsList(final String html) {
|
||||
|
||||
final Document document = Jsoup.parse(html);
|
||||
|
||||
final Map map = new HashMap();
|
||||
|
||||
map.putAll(Parser.one(document));
|
||||
|
||||
map.putAll(Parser.two(document));
|
||||
|
||||
map.putAll(Parser.three(document));
|
||||
|
||||
map.putAll(Parser.four(document));
|
||||
|
||||
map.putAll(Parser.five(document));
|
||||
|
||||
map.putAll(Parser.six(document));
|
||||
|
||||
map.putAll(Parser.seven(document));
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// @Autowired
|
||||
// public TwitchChannelRankingsService service = new TwitchChannelRankingsService();
|
||||
//
|
||||
// public final Integer targetNumberOfChannels = 1500;
|
||||
//
|
||||
// public final Integer channelsPerTwitchTrackerPage = 50;
|
||||
|
||||
// public final List<TwitchChannelRankings> loadSingleSullyGnomeGameFromURL()
|
||||
// throws IOException {
|
||||
//
|
||||
// System.out.println("enter > load top twitchtracker.com channels");
|
||||
// int numberTwitchTrackerPagesToFetch = this.targetNumberOfChannels / this.channelsPerTwitchTrackerPage;
|
||||
//
|
||||
// System.out.println("numberTwitchTrackerPagesToFetch / " + numberTwitchTrackerPagesToFetch);
|
||||
//
|
||||
// List<TwitchChannelRankings> allLoadedTwitchChannels = new ArrayList();
|
||||
//
|
||||
// for (int pageNumber = 1; pageNumber <= numberTwitchTrackerPagesToFetch; pageNumber++) {
|
||||
//
|
||||
// System.out.println("*** loading page / " + pageNumber + " of " + numberTwitchTrackerPagesToFetch);
|
||||
//
|
||||
// List<TwitchChannelRankings> loadedTwitchChannels = this.loadSingleSullyGnomeGameFromURL(pageNumber);
|
||||
//
|
||||
// allLoadedTwitchChannels.addAll(loadedTwitchChannels);
|
||||
//
|
||||
// this.sleep();
|
||||
//
|
||||
// }
|
||||
//
|
||||
// System.out.println("exit < load top 1000x twitchtracker.com channels");
|
||||
//
|
||||
// return allLoadedTwitchChannels;
|
||||
//
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package edu.gsyoung.twitch.upstream.twitchtracker.rankings;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.games.SullyGnomeGamesService;
|
||||
import edu.gsyoung.twitch.data.channel.rankings.TwitchChannelRankings;
|
||||
import edu.gsyoung.twitch.data.channel.rankings.TwitchChannelRankingsService;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("twitchtracker.com/channel/rankings")
|
||||
public class TwitchTrackerChannelRankingsController {
|
||||
|
||||
protected TwitchTrackerChannelRankingsService service = new TwitchTrackerChannelRankingsService();
|
||||
|
||||
protected TwitchChannelRankingsService rankings = new TwitchChannelRankingsService();
|
||||
|
||||
@GetMapping("load")
|
||||
public final List<TwitchChannelRankings> loadTwitchTrackerChannels()
|
||||
throws IOException {
|
||||
|
||||
return this.service.loadTwitchTrackerChannels();
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("load/{pageNumber}")
|
||||
public List<TwitchChannelRankings> loadSingleTwitchTrackerPageByNumber(
|
||||
@PathVariable final Integer pageNumber)
|
||||
throws IOException {
|
||||
|
||||
return this.service.loadTwitchTrackerChannels(pageNumber);
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("truncate")
|
||||
public Boolean truncate() {
|
||||
|
||||
System.out.println("enter > truncate");
|
||||
|
||||
System.out.println(" > truncating database");
|
||||
|
||||
System.out.println("exit < truncate");
|
||||
|
||||
return this.rankings.truncate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,495 @@
|
||||
package edu.gsyoung.twitch.upstream.twitchtracker.rankings;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.sullygnome.games.SullyGnomeGamesService;
|
||||
import edu.gsyoung.twitch.data.channel.rankings.TwitchChannelRankings;
|
||||
import edu.gsyoung.twitch.data.channel.rankings.TwitchChannelRankingsService;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
public class TwitchTrackerChannelRankingsService {
|
||||
|
||||
@Autowired
|
||||
public TwitchChannelRankingsService service = new TwitchChannelRankingsService();
|
||||
|
||||
public final Integer targetNumberOfChannels = 1500;
|
||||
|
||||
public final Integer channelsPerTwitchTrackerPage = 50;
|
||||
|
||||
public void sleep() {
|
||||
|
||||
System.out.println("enter > sleep function");
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
int randomSleepTime = random.nextInt(91) + 90;
|
||||
|
||||
System.out.println("Sleeping for " + randomSleepTime + " seconds");
|
||||
|
||||
try {
|
||||
|
||||
TimeUnit.SECONDS.sleep(randomSleepTime);
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
|
||||
Logger.getLogger(SullyGnomeGamesService.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < sleep function");
|
||||
|
||||
}
|
||||
|
||||
public final List<TwitchChannelRankings> loadTwitchTrackerChannels()
|
||||
throws IOException {
|
||||
|
||||
System.out.println("enter > load top twitchtracker.com channels");
|
||||
|
||||
int numberTwitchTrackerPagesToFetch = this.targetNumberOfChannels / this.channelsPerTwitchTrackerPage;
|
||||
|
||||
System.out.println("numberTwitchTrackerPagesToFetch / " + numberTwitchTrackerPagesToFetch);
|
||||
|
||||
List<TwitchChannelRankings> allLoadedTwitchChannels = new ArrayList();
|
||||
|
||||
for (int pageNumber = 1; pageNumber <= numberTwitchTrackerPagesToFetch; pageNumber++) {
|
||||
|
||||
System.out.println("*** loading page / " + pageNumber + " of " + numberTwitchTrackerPagesToFetch);
|
||||
|
||||
List<TwitchChannelRankings> loadedTwitchChannels = this.loadTwitchTrackerChannels(pageNumber);
|
||||
|
||||
allLoadedTwitchChannels.addAll(loadedTwitchChannels);
|
||||
|
||||
this.sleep();
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < load top 1000x twitchtracker.com channels");
|
||||
|
||||
return allLoadedTwitchChannels;
|
||||
|
||||
}
|
||||
|
||||
public List<TwitchChannelRankings> loadTwitchTrackerChannels(
|
||||
@PathVariable final Integer pageNumber)
|
||||
throws IOException {
|
||||
|
||||
System.out.println("enter > load 50x twitchtracker.com channel rankings from single URL");
|
||||
|
||||
System.out.println("page / " + pageNumber);
|
||||
|
||||
// System.out.println("this.twitchTrackerChannelService / " + this.twitchTrackerChannelService);
|
||||
final String twitchTrackerPageHTML = this.overrideme(pageNumber);
|
||||
|
||||
List<TwitchChannelRankings> loadedTwitchChannels = this.convertHTMLSourceToRecordsList(twitchTrackerPageHTML);
|
||||
|
||||
for (TwitchChannelRankings loadedTwitchChannel : loadedTwitchChannels) {
|
||||
|
||||
this.service.save(loadedTwitchChannel);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit < load 50x single twitchtracker.com channel rankings");
|
||||
|
||||
return loadedTwitchChannels;
|
||||
|
||||
}
|
||||
|
||||
public String overrideme(final Integer pageNumber) {
|
||||
|
||||
System.out.println("enter > fetchSinglePageHTML(live)");
|
||||
|
||||
System.out.println("page / " + pageNumber);
|
||||
|
||||
String url = generateURL(pageNumber);
|
||||
|
||||
System.out.println("url / " + url);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
String htmlContent = null;
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
HttpEntity.EMPTY,
|
||||
String.class);
|
||||
|
||||
if (response.getStatusCodeValue() == 200) {
|
||||
|
||||
htmlContent = response.getBody();
|
||||
|
||||
System.out.println("Retrieved HTML content:");
|
||||
|
||||
System.out.println(htmlContent);
|
||||
|
||||
} else {
|
||||
|
||||
System.out.println("Error: Unexpected status code: " + response.getStatusCodeValue());
|
||||
|
||||
}
|
||||
|
||||
System.out.println("htmlContent / " + htmlContent);
|
||||
|
||||
System.out.println("exit < fetchSinglePageHTML(live)");
|
||||
|
||||
return htmlContent;
|
||||
|
||||
}
|
||||
|
||||
protected String generateURL(final Integer pageNumber) {
|
||||
|
||||
String url = "https://twitchtracker.com/channels/ranking?page=" + pageNumber;
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
protected List<TwitchChannelRankings> convertHTMLSourceToRecordsList(final String html) {
|
||||
|
||||
final Document document = Jsoup.parse(html);
|
||||
|
||||
final Elements tableRows = document.select("#channels tr");
|
||||
|
||||
final List<TwitchChannelRankings> twitchChannels = new ArrayList<>();
|
||||
|
||||
for (Element tableRow : tableRows) {
|
||||
|
||||
Elements elements = tableRow.select("td");
|
||||
|
||||
System.out.println("elements / " + elements);
|
||||
|
||||
TwitchChannelRankings twitchChannel = this.convertTwitchDataElementsToTwitchChannel(elements);
|
||||
|
||||
System.out.println("parsed twitchChannel / " + twitchChannel);
|
||||
|
||||
if (twitchChannel != null) {
|
||||
|
||||
twitchChannels.add(twitchChannel);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return twitchChannels;
|
||||
}
|
||||
|
||||
private TwitchChannelRankings convertTwitchDataElementsToTwitchChannel(Elements elements) {
|
||||
|
||||
System.out.println("enter > convertElementsToChannelRank");
|
||||
|
||||
System.out.println("elements / " + elements);
|
||||
System.out.println("elements length / " + elements.size());
|
||||
|
||||
if (elements.isEmpty()) {
|
||||
System.out.println("SKIPPED");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!elements.select("td:nth-child(1)").text().startsWith("#")) {
|
||||
|
||||
System.out.println("this isn't a dat record");
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
TwitchChannelRankings twitchChannel = new TwitchChannelRankings();
|
||||
|
||||
System.out.println("doing rank math conv");
|
||||
|
||||
Integer rank = Integer.parseInt(elements.select("td:nth-child(1)").text().replaceAll("\\#", ""));
|
||||
|
||||
System.out.println("rank / " + rank);
|
||||
|
||||
twitchChannel.setRank(rank);
|
||||
|
||||
Elements secondElement = elements.select("td:nth-child(2)");
|
||||
|
||||
System.out.println("secondElement / " + secondElement);
|
||||
|
||||
System.out.println("secondElement /size / " + secondElement.size());
|
||||
|
||||
System.out.println(" elements.select(\"td:nth-child(0)\") / " + elements.select("td:nth-child(0)"));
|
||||
System.out.println(" elements.select(\"td:nth-child(1)\") / " + elements.select("td:nth-child(1)"));
|
||||
System.out.println(" elements.select(\"td:nth-child(2)\") / " + elements.select("td:nth-child(2)"));
|
||||
|
||||
if (secondElement.size() >= 1) {
|
||||
|
||||
Element secondTd = secondElement.get(0);
|
||||
|
||||
System.out.println("secondTd / " + secondTd);
|
||||
///////////////////////
|
||||
// Extract the image URL
|
||||
Element imageElement = secondTd.selectFirst("img");
|
||||
String imageUrl = imageElement.attr("src");
|
||||
|
||||
twitchChannel.setLogo(imageUrl);
|
||||
///////////////////////
|
||||
|
||||
Element aElement = secondTd.selectFirst("a");
|
||||
|
||||
String href = "https://twitchtracker.com" + aElement.attr("href");
|
||||
|
||||
twitchChannel.setTag(aElement.attr("href").replace("/", ""));
|
||||
|
||||
twitchChannel.setUrl(href);
|
||||
|
||||
Elements fourthTD = elements.select("td:nth-child(4)");
|
||||
|
||||
System.out.println("fourthTD / " + fourthTD);
|
||||
|
||||
Element spanElement = fourthTD.first();
|
||||
String avgViewersString = spanElement.text();
|
||||
int avgViewers = Integer.parseInt(avgViewersString);
|
||||
|
||||
System.out.println("Extracted average viewers: " + avgViewers);
|
||||
twitchChannel.setAvgViewers(avgViewers);
|
||||
|
||||
extractHoursStreamed(elements, twitchChannel);
|
||||
|
||||
extractAllTimePeakViewers(elements, twitchChannel);
|
||||
|
||||
extractHoursWatched(elements, twitchChannel);
|
||||
|
||||
extractFollowersGained(elements, twitchChannel);
|
||||
|
||||
extractTotalFollowers(elements, twitchChannel);
|
||||
|
||||
extractTotalViews(elements, twitchChannel);
|
||||
|
||||
} else {
|
||||
|
||||
System.out.println("There are less than two elements in the selection.");
|
||||
|
||||
}
|
||||
|
||||
System.out.println("returning / twitchChannel / " + twitchChannel);
|
||||
|
||||
return twitchChannel;
|
||||
|
||||
}
|
||||
|
||||
private void extractHoursStreamed(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extract hours streamed");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(5)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
double hoursStreamedDouble = Double.parseDouble(spanText);
|
||||
|
||||
System.out.println("hours streamed / " + hoursStreamedDouble);
|
||||
|
||||
twitchChannel.setHoursStreamed(hoursStreamedDouble);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extract hours streamed");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
private void extractAllTimePeakViewers(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extractAllTimePeakViewers");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(6)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
Integer allTimePeakViewers = Integer.valueOf(spanText);
|
||||
|
||||
System.out.println("allTimePeakViewers / " + allTimePeakViewers);
|
||||
|
||||
twitchChannel.setAllTimePeakViewers(allTimePeakViewers);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extract hours streamed");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
private void extractHoursWatched(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extractHoursWatched");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(7)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
Integer allTimePeakViewers = Integer.valueOf(spanText);
|
||||
|
||||
System.out.println("allTimePeakViewers / " + allTimePeakViewers);
|
||||
|
||||
twitchChannel.setHoursWatched(allTimePeakViewers);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extractHoursWatched");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
private void extractFollowersGained(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extractFollowersGained");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(9)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
Integer followersGained = Integer.valueOf(spanText);
|
||||
|
||||
System.out.println("followersGained / " + followersGained);
|
||||
|
||||
twitchChannel.setFollowersGained(followersGained);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extractFollowersGained");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
private void extractTotalFollowers(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extractTotalFollowers");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(10)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
Integer totalFollowers = Integer.valueOf(spanText);
|
||||
|
||||
System.out.println("extractTotalFollowers / " + totalFollowers);
|
||||
|
||||
twitchChannel.setTotalFollowers(totalFollowers);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extractTotalFollowers");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
private void extractTotalViews(
|
||||
final Elements elements,
|
||||
final TwitchChannelRankings twitchChannel)
|
||||
throws NumberFormatException {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("enter > extractTotalViews");
|
||||
System.out.println();
|
||||
|
||||
Element fifthChild = elements.select("td:nth-child(11)").get(0);
|
||||
|
||||
System.out.println("fifthChild / " + fifthChild);
|
||||
|
||||
Element spanElement = fifthChild.selectFirst("span");
|
||||
|
||||
System.out.println("spanElement / " + spanElement);
|
||||
|
||||
String spanText = spanElement.text();
|
||||
|
||||
System.out.println("spanText / " + spanText);
|
||||
|
||||
Long totalViews;
|
||||
|
||||
if (spanText.equalsIgnoreCase("--")) {
|
||||
|
||||
totalViews = -1l;
|
||||
|
||||
} else {
|
||||
|
||||
totalViews = Long.valueOf(spanText);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("totalViews / " + totalViews);
|
||||
|
||||
twitchChannel.setTotalViews(totalViews);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("exit < extractTotalViews");
|
||||
System.out.println();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package edu.gsyoung.twitch.upstream.twitchtracker.rankings.stub;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.twitchtracker.rankings.TwitchTrackerChannelRankingsController;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.io.IOException;
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("twitchtracker.com/channel/rankings/stub")
|
||||
public class TwitchTrackerChannelRankingsStubController extends TwitchTrackerChannelRankingsController {
|
||||
|
||||
public TwitchTrackerChannelRankingsStubController() {
|
||||
|
||||
System.out.println("enter > constructor");
|
||||
|
||||
this.service = new TwitchTrackerChannelRankingsStubService();
|
||||
|
||||
System.out.println("this.twitchTrackerChannelService / " + this.service);
|
||||
|
||||
System.out.println("exit < constructor");
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("")
|
||||
public String root() throws IOException {
|
||||
|
||||
return "TwitchTrackerChannelStubController";
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("html")
|
||||
public String getStubHTML() throws IOException {
|
||||
|
||||
System.out.println("enter > display stubbed 50x single twitchtracker.com channel rankings");
|
||||
|
||||
final String twitchTrackerPageHTML = this.service.overrideme(-1);
|
||||
|
||||
System.out.println("exit < display stubbed 50x single twitchtracker.com channel rankings");
|
||||
|
||||
return twitchTrackerPageHTML;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package edu.gsyoung.twitch.upstream.twitchtracker.rankings.stub;
|
||||
|
||||
import edu.gsyoung.twitch.upstream.twitchtracker.rankings.TwitchTrackerChannelRankingsService;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class TwitchTrackerChannelRankingsStubService extends TwitchTrackerChannelRankingsService {
|
||||
|
||||
@Override
|
||||
public String overrideme(final Integer pageNumber) {
|
||||
|
||||
System.out.println("enter > fetchSinglePageHTML(STUB)");
|
||||
|
||||
try {
|
||||
|
||||
ClassPathResource resource = new ClassPathResource("eighteen.html.dat");
|
||||
|
||||
String content = Files.readString(Paths.get(resource.getURI()), StandardCharsets.UTF_8);
|
||||
|
||||
return ResponseEntity.ok(content).getBody();
|
||||
|
||||
} catch (IOException ex) {
|
||||
|
||||
Logger.getLogger(TwitchTrackerChannelRankingsStubService.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("exit > fetchSinglePageHTML(STUB)");
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sleep() {
|
||||
|
||||
System.out.println("enter > sleep function (STUB)");
|
||||
|
||||
System.out.println("exit < sleep function (STUB)");
|
||||
|
||||
}
|
||||
}
|
||||
47
src/main/resources/application.properties
Executable file
47
src/main/resources/application.properties
Executable file
@@ -0,0 +1,47 @@
|
||||
##
|
||||
## application networking configuration
|
||||
##
|
||||
|
||||
server.port=8888
|
||||
|
||||
##
|
||||
## upstream database configuration
|
||||
##
|
||||
|
||||
spring.datasource.url=jdbc:mariadb://${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||
|
||||
spring.datasource.username=${DB_USER}
|
||||
|
||||
spring.datasource.password=${DB_PASS}
|
||||
|
||||
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
|
||||
|
||||
##
|
||||
## Keep the connection alive if idle for a long time (needed in production)
|
||||
##
|
||||
|
||||
spring.datasource.testWhileIdle=true
|
||||
|
||||
spring.datasource.validationQuery=SELECT 1
|
||||
|
||||
##
|
||||
## uncategorized
|
||||
##
|
||||
|
||||
spring.jpa.show-sql=true
|
||||
|
||||
spring.jpa.generate-ddl=false
|
||||
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
|
||||
spring.jpa.open-in-view=true
|
||||
|
||||
mangement.endpoints.web.exposure.include="*"
|
||||
|
||||
server.error.include-stacktrace=always
|
||||
|
||||
server.error.include-message=always
|
||||
|
||||
server.error.include-exception=true
|
||||
|
||||
server.error.include-binding-errors=always
|
||||
1341
src/main/resources/eighteen.stub.html
Normal file
1341
src/main/resources/eighteen.stub.html
Normal file
File diff suppressed because it is too large
Load Diff
716
src/main/resources/kaicenat-2022january.stub.html
Normal file
716
src/main/resources/kaicenat-2022january.stub.html
Normal file
File diff suppressed because one or more lines are too long
BIN
src/main/resources/static/assets/favicon.ico
Executable file
BIN
src/main/resources/static/assets/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
12199
src/main/resources/static/css/styles.css
Executable file
12199
src/main/resources/static/css/styles.css
Executable file
File diff suppressed because it is too large
Load Diff
7
src/main/resources/static/js/scripts.js
Executable file
7
src/main/resources/static/js/scripts.js
Executable file
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Start Bootstrap - Heroic Features v5.0.5 (https://startbootstrap.com/template/heroic-features)
|
||||
* Copyright 2013-2022 Start Bootstrap
|
||||
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-heroic-features/blob/master/LICENSE)
|
||||
*/
|
||||
// This file is intentionally blank
|
||||
// Use this file to add JavaScript to your project
|
||||
1003
src/main/resources/stubs/games/game-grand-theft-auto-five.html
Normal file
1003
src/main/resources/stubs/games/game-grand-theft-auto-five.html
Normal file
File diff suppressed because it is too large
Load Diff
109
src/main/resources/templates/index.html
Normal file
109
src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>
|
||||
|
||||
yankee > sullygnome.com > games
|
||||
|
||||
</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wLFhaGLOxhRLhYZizInMhXYOnSyzGYEV+zVZ38PC5⡀xz4MXvdm0aLwJRQltoWWaL" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://bootswatch.com/journal/bootstrap.min.css">
|
||||
|
||||
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/lux/bootstrap.min.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg bg-primary" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<br />
|
||||
|
||||
<h1>
|
||||
|
||||
yankee > sullygnome.com > games
|
||||
|
||||
</h1>
|
||||
|
||||
<br />
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
|
||||
game -> sample -> gta5 (Live)
|
||||
|
||||
</h2>
|
||||
|
||||
<br />
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
|
||||
<td>[source] sullygnome.com GTA5 page</td>
|
||||
|
||||
<td><a target="_sample" href="https://sullygnome.com/game/Grand_Theft_Auto_V/2023january">
|
||||
|
||||
https://sullygnome.com/game/Grand_Theft_Auto_V/2023january </a></td>
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>[data fetch] See GTA5 page loaded as JSON</td>
|
||||
|
||||
<td><a target="_new" href="https://osiris.yankee.valorantdigital.com/sullygnome.com/games/load/gta5">
|
||||
|
||||
https://osiris.yankee.valorantdigital.com/sullygnome.com/games/load/gta5
|
||||
|
||||
</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-iaucU6enWBC0OJrCWMLD2ur8JKCx9thSYi7+SXv4WBVA1DwYPJ9dKIKaC7cspQvEY" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js" integrity="sha384-Jj66lPWgOzgloaRsncSQx9ikzfnWAu7IWgT6WLHgGOHGGOQMLynH7z9y+Q7VPqm" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
0
test/failure/eval-failure-check-exists.bash
Normal file → Executable file
0
test/failure/eval-failure-check-exists.bash
Normal file → Executable file
0
test/failure/eval-failure-create-new.bash
Normal file → Executable file
0
test/failure/eval-failure-create-new.bash
Normal file → Executable file
0
test/success/eval-success-check-exists.bash
Normal file → Executable file
0
test/success/eval-success-check-exists.bash
Normal file → Executable file
0
test/success/eval-success-create-new.bash
Normal file → Executable file
0
test/success/eval-success-create-new.bash
Normal file → Executable file
194
web/channelrankings.html
Normal file
194
web/channelrankings.html
Normal file
@@ -0,0 +1,194 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>
|
||||
|
||||
Channel Rankings / Twitch Data Acquisition
|
||||
|
||||
</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wLFhaGLOxhRLhYZizInMhXYOnSyzGYEV+zVZ38PC5⡀xz4MXvdm0aLwJRQltoWWaL" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://bootswatch.com/journal/bootstrap.min.css">
|
||||
|
||||
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/vapor/bootstrap.min.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg bg-primary" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Twitch Data Acquisition</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarColor01">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">Home
|
||||
<span class="visually-hidden">(current)</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a target="_new" class="nav-link" href="https://code.softwareshinobi.com/yankee/twitch-data-acquisition.git">Source Code</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<h1>
|
||||
|
||||
twitch > sullygnome.com
|
||||
|
||||
</h1>
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Loaded Records
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
List All Loaded Monthly Game Stats
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
<a target="_new" href="http://veneno.embanet.online:8888/channel/games/monthly/">See All Loaded Data</a>
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Truncate Channel Monthly Game Data</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/channel/games/monthly/truncate">Delete Loaded Data</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Stub Data
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>View the stub page used to create mock data</td>
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/stub/channel/games/monthly/html"> See Stub Page</a></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Load the stub page(s) and it's data into DB</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/stub/channel/games/monthly/load"> Load Stub Page</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Live Data
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>View a sample of the live data</td>
|
||||
<td><a target="_new" href="https://sullygnome.com/channel/kaicenat/2023december/games""> See Live Sample</a></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Load the stub page(s) and it's data into DB</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/channel/games/monthly/load"> Load Live Data</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-iaucU6enWBC0OJrCWMLD2ur8JKCx9thSYi7+SXv4WBVA1DwYPJ9dKIKaC7cspQvEY" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js" integrity="sha384-Jj66lPWgOzgloaRsncSQx9ikzfnWAu7IWgT6WLHgGOHGGOQMLynH7z9y+Q7VPqm" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
194
web/monthlystats.html
Normal file
194
web/monthlystats.html
Normal file
@@ -0,0 +1,194 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>
|
||||
|
||||
Monthly Stats / Twitch Data Acquisition
|
||||
|
||||
</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wLFhaGLOxhRLhYZizInMhXYOnSyzGYEV+zVZ38PC5⡀xz4MXvdm0aLwJRQltoWWaL" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://bootswatch.com/journal/bootstrap.min.css">
|
||||
|
||||
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/vapor/bootstrap.min.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg bg-primary" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Twitch Data Acquisition</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarColor01">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">Home
|
||||
<span class="visually-hidden">(current)</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a target="_new" class="nav-link" href="https://code.softwareshinobi.com/yankee/twitch-data-acquisition.git">Source Code</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<h1>
|
||||
|
||||
twitch > sullygnome.com
|
||||
|
||||
</h1>
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Loaded Records
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
List All Loaded Monthly Game Stats
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
<a target="_new" href="http://veneno.embanet.online:8888/channel/games/monthly/">See All Loaded Data</a>
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Truncate Channel Monthly Game Data</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/channel/games/monthly/truncate">Delete Loaded Data</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Stub Data
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>View the stub page used to create mock data</td>
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/stub/channel/games/monthly/html"> See Stub Page</a></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Load the stub page(s) and it's data into DB</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/stub/channel/games/monthly/load"> Load Stub Page</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="container mt-3">
|
||||
|
||||
<h2>
|
||||
|
||||
Monthly Channel Game Stats > Live Data
|
||||
|
||||
</h2>
|
||||
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td>View a sample of the live data</td>
|
||||
<td><a target="_new" href="https://sullygnome.com/channel/kaicenat/2023december/games""> See Live Sample</a></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>Load the stub page(s) and it's data into DB</td>
|
||||
|
||||
<td><a target="_new" href="http://veneno.embanet.online:8888/sullygnome.com/channel/games/monthly/load"> Load Live Data</a></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-iaucU6enWBC0OJrCWMLD2ur8JKCx9thSYi7+SXv4WBVA1DwYPJ9dKIKaC7cspQvEY" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js" integrity="sha384-Jj66lPWgOzgloaRsncSQx9ikzfnWAu7IWgT6WLHgGOHGGOQMLynH7z9y+Q7VPqm" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
13
web/pages/index.html
Executable file
13
web/pages/index.html
Executable file
@@ -0,0 +1,13 @@
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<script>
|
||||
|
||||
window.location.replace("portal.html");
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
250
web/pages/populate-top-bar.js
Executable file
250
web/pages/populate-top-bar.js
Executable file
@@ -0,0 +1,250 @@
|
||||
|
||||
//var apiURL = "http://veneno.embanet.online:8888";
|
||||
|
||||
//var apiURL = "http://aventador.embanet.online:4242";
|
||||
|
||||
var apiURL = "https://apis.projectchimba.valorantdigital.com";
|
||||
|
||||
function formatNumber(number) {
|
||||
|
||||
return Math.round(number).toLocaleString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function formatDollar(number) {
|
||||
|
||||
return '$ ' + Math.round(number).toLocaleString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
getAccountInformation();
|
||||
|
||||
setInterval(getAccountInformation, 1000 * 10);
|
||||
|
||||
});
|
||||
|
||||
function getAccountInformation() {
|
||||
|
||||
console.debug("enter > getAccountInformation");
|
||||
|
||||
$.ajax({
|
||||
|
||||
type: "GET",
|
||||
|
||||
url: apiURL + "/broker/account",
|
||||
|
||||
contentType: "text/plain",
|
||||
|
||||
crossDomain: true,
|
||||
|
||||
success: function (data, status, exception) {
|
||||
|
||||
updateComponentsWithLiveData(data);
|
||||
|
||||
},
|
||||
|
||||
error: function (exception, status) {
|
||||
|
||||
console.log("exception", exception);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
console.debug("exit < getAccountInformation");
|
||||
|
||||
}
|
||||
|
||||
function updateComponentsWithLiveData(data) {
|
||||
|
||||
$('#account-sidebar-name').html(data.alias);
|
||||
|
||||
$('#account-topright-name').html(data.alias);
|
||||
|
||||
$('#account-bar-nav').html(formatDollar(data.nav));
|
||||
|
||||
$('#account-sidebar-nav').html(formatDollar(data.nav));
|
||||
|
||||
//////
|
||||
|
||||
$('#account-bar-balance').html(formatDollar(data.balance));
|
||||
|
||||
$('#account-bar-position-value').html(formatDollar(data.positionValue));
|
||||
|
||||
$('#account-bar-profit').html(formatDollar(data.pl));
|
||||
|
||||
|
||||
populateLongPositionsTable(data);
|
||||
|
||||
populateShortPositionsTable(data);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
|
||||
|
||||
function populateLongPositionsTable(data) {
|
||||
|
||||
var html = '';
|
||||
|
||||
var rowCount = 0;
|
||||
|
||||
for (var index = data.positions.length - 1; index >= 0; index--) {
|
||||
|
||||
// increment counter and break on threshold break
|
||||
|
||||
rowCount = rowCount + 1;
|
||||
|
||||
if (rowCount > 50) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (data.positions[index].long.units > 0) {
|
||||
|
||||
html += '<tr>';
|
||||
|
||||
html += '<td> <div class="form-check form-check-muted m-0"> <label class="form-check-label"> <input type="checkbox" class="form-check-input"> <i class="input-helper"></i><i class="input-helper"></i><i class="input-helper"></i></label> </div> </td> <td> <img src="assets/images/faces/face1.jpg" alt="image"> <span class="ps-2">';
|
||||
|
||||
html += data.positions[index].instrument;
|
||||
|
||||
html += '</span> </td>';
|
||||
|
||||
// html += '<td class="">' + data.positions[index].instrument + '</td>';
|
||||
|
||||
html += '<td class="">' + formatNumber(data.positions[index].long.units) + '</td>';
|
||||
|
||||
html += '<td class="">' + data.positions[index].long.averagePrice + '</td>';
|
||||
|
||||
var purchasePrice = data.positions[index].long.units * data.positions[index].long.averagePrice;
|
||||
|
||||
console.log("purchasePrice /" + purchasePrice);
|
||||
|
||||
var purchasePrice2 = formatDollar(purchasePrice);
|
||||
|
||||
console.log("purchasePrice2 /" + purchasePrice2);
|
||||
|
||||
//alert(purchasePrice2);
|
||||
|
||||
html += '<td class="">' + purchasePrice2 + '</td>';
|
||||
|
||||
|
||||
|
||||
|
||||
/////
|
||||
|
||||
var profit = data.positions[index].long.unrealizedPL;
|
||||
|
||||
console.log("profit /" + profit);
|
||||
|
||||
var totalpositionworth = parseFloat(purchasePrice) + parseFloat(profit);
|
||||
|
||||
console.log("totalpositionworth /" + totalpositionworth);
|
||||
|
||||
|
||||
html += '<td class="">' + formatDollar(totalpositionworth) + '</td>';
|
||||
|
||||
if (data.positions[index].long.unrealizedPL > 0) {
|
||||
|
||||
html += '<td><div class="badge badge-outline-success">' + formatDollar(data.positions[index].long.unrealizedPL) + '</div></td>';
|
||||
|
||||
} else {
|
||||
|
||||
html += '<td><div class="badge badge-outline-danger"> ' + formatDollar(data.positions[index].long.unrealizedPL) + '</div></td>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
html += '</tr>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$('#table-positions-long > tbody').html(html);
|
||||
|
||||
}
|
||||
|
||||
function populateShortPositionsTable(data) {
|
||||
|
||||
var html = '';
|
||||
|
||||
var rowCount = 0;
|
||||
|
||||
for (var index = data.positions.length - 1; index >= 0; index--) {
|
||||
|
||||
// increment counter and break on threshold break
|
||||
|
||||
rowCount = rowCount + 1;
|
||||
|
||||
if (rowCount > 50) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (data.positions[index].short.units < 0) {
|
||||
|
||||
html += '<tr>';
|
||||
|
||||
html += '<td> <div class="form-check form-check-muted m-0"> <label class="form-check-label"> <input type="checkbox" class="form-check-input"> <i class="input-helper"></i><i class="input-helper"></i><i class="input-helper"></i></label> </div> </td> <td> <img src="assets/images/faces/face1.jpg" alt="image"> <span class="ps-2">';
|
||||
|
||||
html += data.positions[index].instrument;
|
||||
|
||||
|
||||
html += '</span> </td>';
|
||||
|
||||
// html += '<td class="">' + data.positions[index].instrument + '</td>';
|
||||
|
||||
html += '<td class="">' + data.positions[index].short.units + '</td>';
|
||||
html += '<td class="">' + data.positions[index].short.averagePrice + '</td>';
|
||||
|
||||
html += '<td class="">' + data.positions[index].short.units * data.positions[index].short.averagePrice + '</td>';
|
||||
|
||||
html += '<td class="">' + (parseFloat(data.positions[index].short.units * data.positions[index].short.averagePrice) + parseFloat(data.positions[index].short.unrealizedPL)) + '</td>';
|
||||
|
||||
if (data.positions[index].short.unrealizedPL > 0) {
|
||||
html += '<td><div class="badge badge-outline-success">' + data.positions[index].short.unrealizedPL + '</div></td>';
|
||||
} else {
|
||||
html += '<td><div class="badge badge-outline-danger"> $ ' + data.positions[index].short.unrealizedPL + '</div></td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
$('#table-positions-short > tbody').html(html);
|
||||
|
||||
}
|
||||
|
||||
function recycle() {
|
||||
|
||||
html += '<td> $ ' + response.executionReports[index].triggerJustificationReport.sma.toFixed(2) + '</td>';
|
||||
|
||||
html += '<td> $ ' + response.executionReports[index].triggerJustificationReport.price.toFixed(2) + '</td>';
|
||||
|
||||
html += '<td>' + response.executionReports[index].triggerJustificationReport.reason + '</td>';
|
||||
|
||||
if (response.executionReports[index].trigger) {
|
||||
|
||||
html += '<td><span class="badge pill bg-primary">' +
|
||||
response.executionReports[index].trigger + '</span></td>';
|
||||
|
||||
} else {
|
||||
|
||||
html += '<td><span class="badge pill bg-secondary">' +
|
||||
response.executionReports[index].trigger + '</span></td>';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
253
web/pages/portal.html
Executable file
253
web/pages/portal.html
Executable file
@@ -0,0 +1,253 @@
|
||||
|
||||
|
||||
<div id="ssss">
|
||||
|
||||
<div id="apssssps">
|
||||
|
||||
apps
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
target="countdown"
|
||||
|
||||
href="apps/content/article-magick-reloaded/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> app > article magick reloaded
|
||||
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## productivity tools and things
|
||||
##
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<div id="xdd">
|
||||
|
||||
<div id="useddrName">
|
||||
|
||||
productivity
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="countdown"
|
||||
|
||||
href="tools/productivity/10x-countdown-timer/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> tool > 10x timer
|
||||
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="countdown"
|
||||
|
||||
href="tools/productivity/wheel/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> spinning wheel
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## productivity tools and things
|
||||
##
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<div id="xdd">
|
||||
|
||||
<div id="useddrName">
|
||||
|
||||
calculators
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="countdown"
|
||||
|
||||
href="calculators/influencer/subscriber-revenue-projections/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> calc > subscriber revenue
|
||||
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="countdown"
|
||||
|
||||
href="calculators/finance/the-valkyrie-calculators/web/valkyrie-bancolombia.html"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> calc > valkyrie calculator
|
||||
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## next
|
||||
##
|
||||
|
||||
--
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## games
|
||||
##
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<div id="xdd">
|
||||
|
||||
<div id="useddrName">
|
||||
|
||||
games
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="countdown"
|
||||
|
||||
href="games/casino/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> games > casino
|
||||
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## next
|
||||
##>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## games
|
||||
##
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<div id="xdd">
|
||||
|
||||
<div id="useddrName">
|
||||
|
||||
tunnel
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<a
|
||||
|
||||
class="link"
|
||||
|
||||
tdarget="tunnel"
|
||||
|
||||
href="tunnel/"
|
||||
|
||||
>
|
||||
|
||||
<i class=""> </i> tunnel apps
|
||||
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
||||
##
|
||||
## next
|
||||
##>
|
||||
|
||||
19
web/pages/rankings/phaseone.html
Normal file
19
web/pages/rankings/phaseone.html
Normal file
@@ -0,0 +1,19 @@
|
||||
# useful links and stuff
|
||||
|
||||
## stub data loading from twitchtracker.com
|
||||
|
||||
http://localhost:8888/twitch/channel/
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/rankings/stub/truncate
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/rankings/stub/load
|
||||
|
||||
http://localhost:8888/twitch/channel/
|
||||
|
||||
## live loading from twitchtracker.com
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/rankings/truncate
|
||||
|
||||
http://localhost:8888/twitchtracker.com/channel/rankings/load
|
||||
|
||||
http://localhost:8888/twitch/channel/
|
||||
39
web/pages/rankings/teststub.bash
Executable file
39
web/pages/rankings/teststub.bash
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
set -x
|
||||
|
||||
reset
|
||||
|
||||
clear
|
||||
|
||||
echo
|
||||
echo "TEST / data / view application channel data"
|
||||
echo
|
||||
|
||||
curl http://localhost:8888/twitch/channel/
|
||||
|
||||
echo
|
||||
echo "TEST / operation / delete all application channel data from database"
|
||||
echo
|
||||
|
||||
curl http://localhost:8888/twitchtracker.com/channel/rankings/truncate
|
||||
|
||||
echo
|
||||
echo "TEST / data / view application channel data"
|
||||
echo
|
||||
|
||||
curl http://localhost:8888/twitch/channel/
|
||||
|
||||
echo
|
||||
echo "TEST / operation / load application channel data from twitchtracker.com"
|
||||
echo
|
||||
|
||||
curl http://localhost:8888/twitchtracker.com/channel/rankings/stub/load
|
||||
|
||||
echo
|
||||
echo "TEST / data / view application channel data"
|
||||
echo
|
||||
|
||||
curl http://localhost:8888/twitch/channel/
|
||||
Reference in New Issue
Block a user