automated terminal push
This commit is contained in:
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>
|
||||
Reference in New Issue
Block a user