automated terminal push

This commit is contained in:
Your Name
2025-02-06 13:09:57 -05:00
parent 9a787b2a58
commit 09d4e08831
80 changed files with 22592 additions and 147 deletions

View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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> {
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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> {
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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 {
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
//
// }
}

View File

@@ -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;
//
// }

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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)");
}
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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>
&nbsp;&nbsp; yankee > sullygnome.com > games
</h1>
<br />
<div class="container mt-3">
<h2>
&nbsp;&nbsp;&nbsp;&nbsp;
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>