-
Notifications
You must be signed in to change notification settings - Fork 0
/
flower.py
122 lines (94 loc) · 3.72 KB
/
flower.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from datetime import datetime
import requests
from bs4 import BeautifulSoup, ResultSet
from config import FLOWER_SESSION
from ft_types import FlowerSongData, Game
from tachi import get_recent_session
def flower_get(url: str) -> BeautifulSoup:
s = requests.Session()
s.cookies.set("flower_session", FLOWER_SESSION)
res = s.get(url)
return BeautifulSoup(res.text, "html.parser")
# This now stores the home page so a request isnt made for every single playtype
def find_profile_url(game: Game):
if find_profile_url.home_page is None:
find_profile_url.home_page = flower_get("https://projectflower.eu")
button = find_profile_url.home_page.find("a", attrs={"title": game.flower_name})
if button is None:
raise Exception("Game not found on your profile")
return button["href"]
find_profile_url.home_page = None
def _should_score_exist(score: FlowerSongData, date: datetime) -> bool:
recent_song = score.header[-1].find("small").text
recent_date = datetime.strptime(recent_song, "%Y-%m-%d %I:%M %p")
return recent_date <= date
def _parse_page(
page_songs: ResultSet, page: BeautifulSoup, iidx: bool
) -> list[FlowerSongData]:
index = 0
songs: list[FlowerSongData] = list[FlowerSongData]()
for song in page_songs:
if iidx:
script = page.find_all("script")[index + 4].text
else:
script = None
songs.append(FlowerSongData(song, script))
return songs
def iter_pages(start_url):
url = start_url
while url is not None:
if url in iter_pages.page_cache:
# page is cached
yield iter_pages.page_cache[url][0]
url = iter_pages.page_cache[url][1]
else:
# get current page and parse
soup = flower_get(url)
song_row = soup.find_all("tr", class_="accordion-toggle")
if len(song_row) == 0:
break
parsed = _parse_page(song_row, soup, "iidx" in url)
# get next url.
paginator = soup.find("ul", class_="pagination")
next_button = paginator.find_all("li")[-1].find("a") if paginator else None
next_url = next_button["href"] if next_button else None
iter_pages.page_cache[url] = (parsed, next_url)
yield parsed
url = next_url
iter_pages.page_cache = {}
def parse_pages(game: Game, pages: list[int]) -> list[FlowerSongData]:
url = find_profile_url(game)
songs: list[FlowerSongData] = list[
FlowerSongData
]() # huh type checking complains if you use []
if pages == "all":
for page in iter_pages(url):
songs.extend(page)
return songs
if pages == "recent":
date: datetime.date
try:
session = get_recent_session(game.tachi_gpt)
date = datetime.fromtimestamp(
session["body"]["session"]["timeEnded"] / 1000
)
except RuntimeError:
print("Could not find any sessions. Aborting")
exit(1)
for page in iter_pages(url):
songs.extend(page)
if _should_score_exist(page[-1], date):
break
# filter out songs that should already be in tachi
return list(filter(lambda x: not _should_score_exist(x, date), songs))
for page in pages:
soup = flower_get(f"{url}?page={page}")
song_row = soup.find_all("tr", class_="accordion-toggle")
if len(song_row) == 0:
return songs
songs.extend(_parse_page(song_row, soup, "iidx" in url))
return songs
def parse_date(date_str: str) -> int:
date_format = "%Y-%m-%d %I:%M %p"
date = datetime.strptime(date_str, date_format)
return int(date.timestamp() * 1000)