Skip to content

Commit 468fd32

Browse files
author
Luca Sepe
committed
first commit
0 parents  commit 468fd32

File tree

3 files changed

+347
-0
lines changed

3 files changed

+347
-0
lines changed

.gitignore

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
2+
# Created by https://www.gitignore.io/api/java,maven,intellij,eclipse,netbeans
3+
4+
### Eclipse ###
5+
6+
.metadata
7+
bin/
8+
tmp/
9+
*.tmp
10+
*.bak
11+
*.swp
12+
*~.nib
13+
local.properties
14+
.settings/
15+
.loadpath
16+
.recommenders
17+
18+
# Eclipse Core
19+
.project
20+
21+
# External tool builders
22+
.externalToolBuilders/
23+
24+
# Locally stored "Eclipse launch configurations"
25+
*.launch
26+
27+
# PyDev specific (Python IDE for Eclipse)
28+
*.pydevproject
29+
30+
# CDT-specific (C/C++ Development Tooling)
31+
.cproject
32+
33+
# JDT-specific (Eclipse Java Development Tools)
34+
.classpath
35+
36+
# Java annotation processor (APT)
37+
.factorypath
38+
39+
# PDT-specific (PHP Development Tools)
40+
.buildpath
41+
42+
# sbteclipse plugin
43+
.target
44+
45+
# Tern plugin
46+
.tern-project
47+
48+
# TeXlipse plugin
49+
.texlipse
50+
51+
# STS (Spring Tool Suite)
52+
.springBeans
53+
54+
# Code Recommenders
55+
.recommenders/
56+
57+
### Intellij ###
58+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
59+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
60+
61+
# User-specific stuff:
62+
.idea/**/workspace.xml
63+
.idea/**/tasks.xml
64+
.idea/**/encodings.xml
65+
.idea/**/compiler.xml
66+
.idea/**/misc.xml
67+
.idea/**/modules.xml
68+
69+
# Sensitive or high-churn files:
70+
.idea/**/dataSources/
71+
.idea/**/dataSources.ids
72+
.idea/**/dataSources.xml
73+
.idea/**/dataSources.local.xml
74+
.idea/**/sqlDataSources.xml
75+
.idea/**/dynamic.xml
76+
.idea/**/uiDesigner.xml
77+
78+
# Gradle:
79+
.idea/**/gradle.xml
80+
.idea/**/libraries
81+
82+
# Mongo Explorer plugin:
83+
.idea/**/mongoSettings.xml
84+
85+
## File-based project format:
86+
*.iws
87+
*.iml
88+
.idea/
89+
90+
## Plugin-specific files:
91+
92+
# IntelliJ
93+
/out/
94+
95+
# mpeltonen/sbt-idea plugin
96+
.idea_modules/
97+
98+
# JIRA plugin
99+
atlassian-ide-plugin.xml
100+
101+
# Crashlytics plugin (for Android Studio and IntelliJ)
102+
com_crashlytics_export_strings.xml
103+
crashlytics.properties
104+
crashlytics-build.properties
105+
fabric.properties
106+
107+
### Intellij Patch ###
108+
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
109+
110+
# *.iml
111+
# modules.xml
112+
# .idea/misc.xml
113+
# *.ipr
114+
115+
### Java ###
116+
# Compiled class file
117+
*.class
118+
119+
# Log file
120+
*.log
121+
122+
# BlueJ files
123+
*.ctxt
124+
125+
# Mobile Tools for Java (J2ME)
126+
.mtj.tmp/
127+
128+
# Package Files #
129+
*.jar
130+
*.war
131+
*.ear
132+
*.zip
133+
*.tar.gz
134+
*.rar
135+
136+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
137+
hs_err_pid*
138+
139+
### Maven ###
140+
target/
141+
pom.xml.tag
142+
pom.xml.releaseBackup
143+
pom.xml.versionsBackup
144+
pom.xml.next
145+
release.properties
146+
dependency-reduced-pom.xml
147+
buildNumber.properties
148+
.mvn/timing.properties
149+
150+
# Exclude maven wrapper
151+
!/.mvn/wrapper/maven-wrapper.jar
152+
153+
### NetBeans ###
154+
nbproject/private/
155+
build/
156+
nbbuild/
157+
dist/
158+
nbdist/
159+
.nb-gradle/
160+
161+
# End of https://www.gitignore.io/api/java,maven,intellij,eclipse,netbeans

main.go

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"log"
7+
"net/url"
8+
"os"
9+
10+
"github.com/gocolly/colly"
11+
"github.com/lucasepe/go-ps4/utils"
12+
)
13+
14+
type Game struct {
15+
Title string
16+
Cover string
17+
Details string
18+
Price string
19+
}
20+
21+
var (
22+
version string
23+
date string
24+
)
25+
26+
func visit(rootUrl string) chan Game {
27+
ch := make(chan Game)
28+
29+
go func() {
30+
// [\p{Sc}]
31+
32+
collector := colly.NewCollector(
33+
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0"),
34+
colly.AllowedDomains("store.playstation.com"),
35+
//colly.Async(true),
36+
//colly.CacheDir("./playstation-store-cache/"),
37+
)
38+
39+
collector.OnHTML("div[class*='grid-cell--game']", func(e *colly.HTMLElement) {
40+
cover := e.ChildAttr("div.grid-cell__thumbnail img[src^='https://store.playstation.com/store/api/chihiro']", "src")
41+
42+
title := e.ChildText("div.grid-cell__body > a")
43+
details := e.ChildText("div.grid-cell__bottom > grid-cell__details-container grid-cell__left-detail--detail-2")
44+
price := e.ChildText("div.grid-cell__bottom > div.grid-cell__footer h3.price-display__price")
45+
46+
if price != "" {
47+
ch <- Game{Title: title, Cover: cover, Details: details, Price: price}
48+
}
49+
})
50+
51+
collector.OnHTML("div.grid-footer-controls a.paginator-control__next", func(e *colly.HTMLElement) {
52+
link := e.Request.AbsoluteURL(e.Attr("href"))
53+
e.Request.Visit(link)
54+
})
55+
56+
collector.OnRequest(func(r *colly.Request) {
57+
//log.Println("visiting", r.URL.String())
58+
})
59+
60+
collector.Visit(rootUrl)
61+
62+
collector.Wait()
63+
64+
close(ch)
65+
}()
66+
67+
return ch
68+
}
69+
70+
func showVersion() {
71+
fmt.Printf("PS4 Games CLI (build:%s@%s)\n", version, date)
72+
}
73+
74+
/**
75+
* NIX: go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~10,4%-%date:~4,2%-%date:~7,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"
76+
*
77+
* WIN: go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~-4%-%date:~3,2%-%date:~6,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"
78+
*/
79+
func main() {
80+
81+
weeklyDealsUrls := map[string]string{
82+
"it": "it-IT/grid/STORE-MSF75508-DOTW1",
83+
"en": "en-US/grid/STORE-MSF77008-WEEKLYDEALS",
84+
}
85+
86+
searchUrls := map[string]string{
87+
"it": "it-it/search/",
88+
"en": "en-US/search/",
89+
}
90+
91+
addonsUrls := map[string]string{
92+
"en": "en-US/grid/STORE-MSF77008-NEWPS4ADDONSCATE",
93+
"it": "it-it/grid/STORE-MSF75508-ADDONSSEEALL",
94+
}
95+
96+
allGamesUrls := map[string]string{
97+
"en": "en-US/grid/STORE-MSF77008-PS4ALLGAMESCATEG",
98+
"it": "it-it/grid/STORE-MSF75508-PS4CAT",
99+
}
100+
101+
optVersion := flag.Bool("version", false, "show app version")
102+
optLang := flag.String("lang", "it", "language (it, en)")
103+
optAddons := flag.Bool("addons", false, "show also extra contents")
104+
optFree := flag.Bool("free", false, "show only free titles")
105+
optWeeklyDeals := flag.Bool("weekly-deals", false, "show only weekly deals titles")
106+
optSearch := flag.String("search", "", "search for specified title")
107+
108+
flag.Parse()
109+
110+
if *optVersion {
111+
showVersion()
112+
os.Exit(0)
113+
}
114+
115+
var uriPath string
116+
if *optAddons {
117+
uriPath = addonsUrls[*optLang]
118+
} else if *optSearch != "" {
119+
uriPath = searchUrls[*optLang]
120+
} else if *optWeeklyDeals {
121+
uriPath = weeklyDealsUrls[*optLang]
122+
} else {
123+
uriPath = allGamesUrls[*optLang]
124+
}
125+
126+
u, err := url.Parse(fmt.Sprintf("https://store.playstation.com/%s", uriPath))
127+
if err != nil {
128+
log.Fatal(err)
129+
}
130+
131+
if *optSearch == "" {
132+
q := u.Query()
133+
q.Add("direction", "asc")
134+
q.Add("sort", "price")
135+
q.Add("platform", "ps4")
136+
137+
if !*optAddons && !*optWeeklyDeals {
138+
q.Add("gameContentType", "games,bundles")
139+
}
140+
141+
if !*optWeeklyDeals {
142+
if *optFree {
143+
q.Add("price", "0-0")
144+
} else if *optLang == "it" {
145+
q.Add("price", "1000-1999,2000-2999,3000-3999")
146+
}
147+
}
148+
149+
u.RawQuery = q.Encode()
150+
151+
} else {
152+
u, err = url.Parse(fmt.Sprintf("https://store.playstation.com/%s/%s", uriPath, *optSearch))
153+
if err != nil {
154+
log.Fatal(err)
155+
}
156+
}
157+
158+
for g := range visit(u.String()) {
159+
fmt.Printf("%s %s\n", utils.RightPad(g.Title, 68, "."), utils.RightPad(g.Price, 7, " "))
160+
}
161+
}

utils/pad.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package utils
2+
3+
import (
4+
"strings"
5+
"unicode/utf8"
6+
)
7+
8+
func times(str string, n int) (out string) {
9+
var sb strings.Builder
10+
for i := 0; i < n; i++ {
11+
sb.WriteString(str)
12+
}
13+
return sb.String()
14+
}
15+
16+
// Left left-pads the string with pad up to len runes
17+
// len may be exceeded if
18+
func LeftPad(str string, len int, pad string) string {
19+
return times(pad, len-utf8.RuneCountInString(str)) + str
20+
}
21+
22+
// Right right-pads the string with pad up to len runes
23+
func RightPad(str string, len int, pad string) string {
24+
return str + times(pad, len-utf8.RuneCountInString(str))
25+
}

0 commit comments

Comments
 (0)