2 Commits

Author SHA1 Message Date
Sweetbread 85d1e2be85 tmp 2026-02-10 10:27:45 +03:00
Sweetbread e6bc69aa3e Add rtime for steam 2026-02-07 20:05:29 +03:00
24 changed files with 349 additions and 171 deletions
-2
View File
@@ -11,8 +11,6 @@ from flask import Flask
app = Flask(__name__, static_folder=None, subdomain_matching=True)
app.jinja_env.add_extension('pypugjs.ext.jinja.PyPugJSExtension')
app.before_request(locale.before_request)
app.context_processor(locale.inject_translations)
+2 -7
View File
@@ -33,11 +33,6 @@ def tmsmp(sec: int) -> str:
days = round(sec / 86400, 1)
return f"{days:.0f} d" if days.is_integer() else f"{days:.1f} d"
def utmsmp(unix: int) -> str:
return datetime \
.utcfromtimestamp(unix) \
.strftime('%Y-%m-%d %H:%M:%S')
def rtmsmp(unix: int) -> str:
return tmsmp(int(time() - unix))
@@ -53,7 +48,8 @@ def render_tmpl(filename: str, **kwargs) -> str:
template_path = os.path.join("risdeveau/templates", filename)
return minify(
render_template(template_path, **kwargs),
remove_empty_space=True
remove_empty_space=True,
remove_all_empty_space=True
)
@bp.route("/static/<path:filename>")
@@ -77,7 +73,6 @@ args = {
"lb": lb_data,
"steam": steam_data,
"tmsmp": tmsmp,
"utmsmp": utmsmp,
"rtmsmp": rtmsmp
}
+3 -2
View File
@@ -34,12 +34,13 @@ data = {
def modify_game_list(json: dict) -> dict:
if 'games' in json.keys():
apps = (3301060, 404790, 1281930, 1920960, 1325960, 431960)
new_games = []
new_games = {}
for i, g in enumerate(json['games']):
if g['appid'] not in apps:
json['games'][i]['h_cover'] = f"https://shared.fastly.steamstatic.com/store_item_assets//steam/apps/{g['appid']}/header.jpg"
json['games'][i]['v_cover'] = f"https://shared.fastly.steamstatic.com/store_item_assets//steam/apps/{g['appid']}/library_600x900.jpg"
new_games.append(json['games'][i])
new_games[g['appid']] = json['games'][i]
json['games'] = new_games
return json
@@ -65,4 +65,72 @@ document.addEventListener('alpine:init', () => {
}
},
}));
Alpine.data('steam_rtime', (unixTimestamp) => ({
targetDate: new Date(unixTimestamp * 1000),
timeString: '',
timer: null,
interval: 1000,
colorClasses: {
green: 't-green',
yellow: 't-yellow',
orange: 't-orange',
red: 't-red'
},
currentColor: 'green',
get textColorClass() {
return this.colorClasses[this.currentColor];
},
init() {
this.updateTime();
this.timer = setInterval(() => this.updateTime(), this.interval);
this.$el.addEventListener('alpine:removing', () => {
if (this.interval) clearInterval(this.interval);
});
},
updateTime() {
const now = new Date();
const diffInMinutes = Math.floor((now - this.targetDate) / 60000);
const diffInHours = Math.floor(diffInMinutes / 60);
const diffInDays = Math.floor(diffInHours / 24);
const diffInMonths = Math.floor(diffInDays / 30);
let newInterval = this.interval;
if (diffInMinutes < 60) {
this.timeString = `${diffInMinutes} m ago`;
newInterval = 10000;
} else if (diffInHours < 24) {
this.timeString = `${diffInHours} h ago`;
newInterval = 60000;
} else if (diffInDays < 30) {
this.timeString = `${diffInDays} d ago`;
clearInterval(this.timer);
} else {
this.timeString = `${diffInMonths} mth ago`;
clearInterval(this.timer);
}
if (diffInHours < 12) {
this.currentColor = 'green';
} else if (diffInDays < 1) {
this.currentColor = 'yellow';
} else if (diffInMonths < 6) {
this.currentColor = 'orange'
} else {
this.currentColor = 'red';
}
if (this.interval != newInterval) {
clearInterval(this.timer)
this.timer = setInterval(() => this.updateTime(), newInterval);
}
},
}));
});
@@ -51,7 +51,27 @@ h3 {
.steam {
.block {
display: flex;
&:not(.popup) {
display: flex;
position: relative;
z-index: 1;
}
&.popup {
margin-top: -.5rem;
padding-top: 1rem;
background-color: theme.$mantle;
transition: all ease-out 300ms;
&.enter {}
&.off {
margin-bottom: -.5rem;
padding: 0 .5rem;
opacity: 0;
transform: translateY(-100%);
}
}
img {
height: 7rem;
+16
View File
@@ -0,0 +1,16 @@
<div>
<div class="88-31">
<a href="https://chest.lair.moe" class="disabled">
<img src="/static/img/88x31/gf.png"/>
</a>
<a href="https://preview.about.akarpov.ru" id="pie">
<img src="/static/img/88x31/withpie.gif"/>
</a>
</div>
<div class="88-31">
<a href="https://g.lair.moe/Sweetbread/nixos-config">
<img src="/static/img/88x31/nixos.webp"/>
</a>
<img src="/static/img/88x31/teto.webp"/>
</div>
</div>
-13
View File
@@ -1,13 +0,0 @@
div
.88-31
a.disabled(href="https://chest.lair.moe")
img(src="/static/img/88x31/gf.png")
a#pie(href="https://preview.about.akarpov.ru")
img(src="/static/img/88x31/withpie.gif")
.88-31
a(href="https://g.lair.moe/Sweetbread/nixos-config")
img(src="/static/img/88x31/nixos.webp")
img(src="/static/img/88x31/teto.webp")
@@ -0,0 +1,48 @@
<div class="block">
<h3>Development</h3>
<div class="blocks badges">
<a class="block" href="//g.lair.moe/Sweetbread">
<img class="icon" src="/static/icon/service/gitea.webp" />
Gitea
</a>
<a class="block" href="https://github.com/VerySweetBread">
<img class="icon" src="https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png" />
GitHub
</a>
<a class="block" href="https://git.kolibrios.org/Sweetbread">
<img class="icon" src="https://git.kolibrios.org/assets/img/logo.svg" />
KolibriOS Git
</a>
</div>
<h3>Contacts</h3>
<div class="blocks badges">
<a class="block" href="https://matrix.to/#/@risdeveau:codrs.ru">
<img class="icon" src="https://matrix.org/assets/favicon.ico" />
Matrix
</a>
<a class="block" href="//b.lair.moe/@risdeveau">
<img class="icon" src="/static/icon/service/sharkey.webp" />
Fediverse
</a>
<a class="block" href="https://discord.com/users/459823895256498186">
<img class="icon" src="https://cdn.prod.website-files.com/6257adef93867e50d84d30e2/66e3d80db9971f10a9757c99_Symbol.svg" />
Discord
</a>
<a class="block" href="mailto:risdeveau@lair.moe">
Mail
</a>
</div>
<h3>Game accounts</h3>
<div class="blocks badges">
<a class="block" href="https://steamcommunity.com/id/risdeveau">
<img class="icon" src="https://store.steampowered.com/favicon.ico" />
Steam
</a>
<a class="block" href="https://gamebanana.com/members/3899828">
<img class="icon" src="https://images.gamebanana.com/static/img/favicon/favicon.ico" />
GameBanana
</a>
</div>
</div>
@@ -1,41 +0,0 @@
.block
h3 Development
.blocks.badges
a.block(href="//g.lair.moe/Sweetbread")
img.icon(src="/static/icon/service/gitea.webp")
| Gitea
a.block(href="https://github.com/VerySweetBread")
img.icon(src="https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png")
| GitHub
a.block(href="https://git.kolibrios.org/Sweetbread")
img.icon(src="https://git.kolibrios.org/assets/img/logo.svg")
| KolibriOS Git
h3 Contacts
.blocks.badges
a.block(href="https://matrix.to/#/@risdeveau:lair.moe")
img.icon(src="https://matrix.org/assets/favicon.ico")
| Matrix
a.block(href="//b.lair.moe/@risdeveau")
img.icon(src="/static/icon/service/sharkey.webp")
| Fediverse
a.block(href="https://discord.com/users/459823895256498186")
img.icon(src="https://cdn.prod.website-files.com/6257adef93867e50d84d30e2/66e3d80db9971f10a9757c99_Symbol.svg")
| Discord
a.block(href="mailto:risdeveau@lair.moe")
| Mail
h3 Game accounts
.blocks.badges
a.block(href="https://steamcommunity.com/id/risdeveau")
img.icon(src="https://store.steampowered.com/favicon.ico")
| Steam
a.block(href="https://gamebanana.com/members/3899828")
img.icon(src="https://images.gamebanana.com/static/img/favicon/favicon.ico")
| GameBanana
+19
View File
@@ -0,0 +1,19 @@
<div>
<h3>Wallets</h3>
<div class="blocks qr">
<div class="block qr">
<p>POL, BNB</p>
<img src="/static/img/wallets/evm.webp">
</div>
<div class="block qr">
<p>TON</p>
<img src="/static/img/wallets/ton.webp">
</div>
<div class="block qr">
<p>XMR</p>
<img src="/static/img/wallets/xmr.webp">
</div>
</div>
</div>
-14
View File
@@ -1,14 +0,0 @@
div
h3 Wallets
.blocks.qr
.block.qr
p POL, BNB
img(src="/static/img/wallets/evm.webp")
.block.qr
p TON
img(src="/static/img/wallets/ton.webp")
.block.qr
p XMR
img(src="/static/img/wallets/xmr.webp")
+1 -1
View File
@@ -50,7 +50,7 @@
'donate',
'88x31'
) %}
{% include 'risdeveau/templates/%s.pub' % m %}
{% include 'risdeveau/templates/%s.htm' % m %}
{% endfor %}
</main>
</body>
+50
View File
@@ -0,0 +1,50 @@
<div class="block">
<table>
<tr>
<th>DoB</th>
<td>2005-01-13</td>
</tr>
<tr>
<th>Languages</th>
<td>
<table>
<tr>
<td>Russian</td>
<td>Native</td>
</tr>
<tr>
<td>English</td>
<td>B2</td>
</tr>
<tr>
<td>French</td>
<td>A1?</td>
</tr>
<tr>
<td>German</td>
<td>A2?</td>
</tr>
<tr>
<td>Japanese</td>
<td>Beginner</td>
</tr>
</table>
</td>
</tr>
<tr>
<th>Student</th>
<td>
<table>
<tr>
<td>Programmer</td>
<td>2/4yr.</td>
</tr>
<tr>
<td>Translator</td>
<td>2/3yr.</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
-35
View File
@@ -1,35 +0,0 @@
.block
table
tr
th DoB
td 2005-01-13
tr
th Languages
td
table
tr
td Russian
td Native
tr
td English
td B2
tr
td French
td A1?
tr
td German
td A2?
tr
td Japanese
td Beginner
tr
th Student
td
table
tr
td Programmer
td 2.5/4yr.
tr
td Translator
td 2.5/3yr.
+69 -13
View File
@@ -1,3 +1,7 @@
{% if request.headers.get('hx-request') != "true" %}
<div x-data='{ "current": null, "total_mode": "T" }' class="mt-1">
{% endif %}
<div
class="block steam"
hx-get="/m/steam"
@@ -10,10 +14,12 @@
>
<h2><a href="https://steamcommunity.com/id/risdeveau">Steam</a></h2>
{{ steam.caches.recent.status }}
{{ steam.caches.owned.status }}
{% if steam.caches.recent.data.games %}
<h3>Recently played:</h3>
{% for g in steam.caches.recent.data.games %}
<a href="https://store.steampowered.com/app/{{ g.appid }}" class="block">
{% for g in steam.caches.recent.data.games.values() %}
<div href="https://store.steampowered.com/app/{{ g.appid }}" class="block">
<picture>
<source media="(max-width: 45rem)" srcset="{{ g.v_cover }}">
<img src="{{ g.h_cover }}">
@@ -22,14 +28,35 @@
<div>
<strong>{{ g.name }}</strong>
<p>Played last 2 weeks: {{ tmsmp(g.playtime_2weeks*60) }}
<p>
Total played:
{{ tmsmp(g.playtime_linux_forever*60) }} (<abbr title="On Linux">L</abbr>) +
{{ tmsmp(g.playtime_windows_forever*60) }} (<abbr title="On Windows">W</abbr>) =
{{ tmsmp(g.playtime_forever*60) }} (<abbr title="Total">T</abbr>)
</p>
<div>
<p
x-data='{ playtime: { L: "{{ tmsmp(g.playtime_linux_forever*60) }}", W: "{{ tmsmp(g.playtime_windows_forever*60) }}", T: "{{ tmsmp(g.playtime_forever*60) }}" }}'
x-text="`Total played: ${playtime[total_mode]}`"
>
</p>
<div>
<button @click="total_mode = 'L'" :class="total_mode == 'L' && 't-green'">L</button>
<button @click="total_mode = 'W'" :class="total_mode == 'W' && 't-green'">W</button>
<button @click="total_mode = 'T'" :class="total_mode == 'T' && 't-green'">T</button>
</div>
</div>
{% if steam.caches.owned.data.games %}
{% if steam.caches.owned.data.games[g.appid] %}
<p
x-data="steam_rtime({{ steam.caches.owned.data.games[g.appid].rtime_last_played }})"
x-text="`Last played: ${timeString}`"
:class="textColorClass"
></p>
{% else %}
<p class="t-red">Last played: Unknown</p>
{% endif %}
{% endif %}
</div>
</a>
</div>
{% endfor %}
<p
x-data="rtime({{steam.caches.recent.last_updated}})"
@@ -39,9 +66,13 @@
{% if steam.caches.owned.data.games %}
<h3>Top played games:</h3>
{% set owned_games = steam.caches.owned.data.games | sort(attribute="playtime_forever", reverse=true) %}
{% set owned_games = steam.caches.owned.data.games.values() | sort(attribute="playtime_forever", reverse=true) %}
{% for g in owned_games[:5] %}
<a href="https://store.steampowered.com/app/{{ g.appid }}" class="block">
<div
@click='current == {{ g.appid }} ? current = null : current = {{ g.appid }}'
href="https://store.steampowered.com/app/{{ g.appid }}"
class="block"
>
<picture>
<source media="(max-width: 45rem)" srcset="{{ g.v_cover }}">
<img src="{{ g.h_cover }}">
@@ -56,14 +87,39 @@
{{ tmsmp(g.playtime_forever*60) }} (<abbr title="Total">T</abbr>)
</p>
{% if g.rtime_last_played != 0 %}
<p>Last played: {{ utmsmp(g.rtime_last_played) }}</p>
<p
x-data="steam_rtime({{ g.rtime_last_played }})"
x-text="`Last played: ${timeString}`"
:class="textColorClass"
></p>
{% endif %}
</div>
</a>
</div>
<div
class="block popup"
x-show="current == {{ g.appid }}"
x-transition:enter-start="off"
x-transition:leave-end="off"
>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
<p>Some info</p>
</div>
{% endfor %}
<p
x-data="rtime({{steam.caches.owned.last_updated}})"
x-text="`Last updated: ${timeString}`"
></p>
{% endif %}
</div>
{% if request.headers.get('hx-request') != "true" %}
</div>
{% endif %}
+2 -2
View File
@@ -21,8 +21,8 @@ def index():
@bp.route("/host")
def host():
return render_tmpl('host.pug')
return render_tmpl('host.html')
@bp.route("/us")
def us():
return render_tmpl('us.pug')
return render_tmpl('us.html')
+6
View File
@@ -1,5 +1,11 @@
@use "catppuccin" as theme;
.m {
&t {
&-1 { margin-top: .5rem; }
}
}
.t {
&-red { color: theme.$red; }
&-orange { color: theme.$peach; }
+21
View File
@@ -0,0 +1,21 @@
{% extends 'base.tmpl' %}
{% block title %}{{ _('about host') }}{% endblock %}
{% block content %}
<a href="https://play2go.cloud/?ref_id=4baFoOIp5QE" target="_blank" class="block">
<strong>{{ _("host:hoster") }}</strong>: play2go
<p>{{ _('host:hoster_descr') }}</p>
</a>
<div class="block">
<strong>{{ _("host:specifications") }}</strong>:
<ul>
<li>CPU: Ryzen 9@3.4GHz (4 cores)</li>
<li>RAM: 8 GB</li>
<li>SSD: 150 GB</li>
<li>ETH: 500Mb/s</li>
<li>Loc: Deutschland, Frankfurt am Main</li>
</ul>
</div>
{% endblock %}
-20
View File
@@ -1,20 +0,0 @@
extends base.tmpl
block title
= _('about host')
block content
a.block(href="https://play2go.cloud/?ref_id=4baFoOIp5QE" target="_blank")
strong= _("host:hoster")
| : play2go
p= _('host:hoster_descr')
.block
strong= _("host:specifications")
| :
ul
li CPU: Ryzen 9@3.4GHz (4 cores)
li RAM: 8 GB
li SSD: 150 GB
li ETH: 500Mb/s
li Loc: Deutschland, Frankfurt am Main
+1 -1
View File
@@ -22,7 +22,7 @@
</a>
<div class="block">
<p><a href="https://m.lair.moe" target="_blank"><strong>Matrix</strong></a> &mdash; {{ _('index.descr:matrix') }}</p>
<p><a href="https://m.codrs.ru" target="_blank"><strong>Matrix</strong></a> &mdash; {{ _('index.descr:matrix') }}</p>
<p><a href="https://c.lair.moe" target="_blank"><strong>Copyparty</strong></a> &mdash; {{ _('index.descr:copyparty') }}</p>
<p><a href="https://tools.lair.moe" target="_blank"><strong>IT-tools</strong></a> &mdash; {{ _('index.descr:tools') }}</p>
<p><a href="https://vert.lair.moe" target="_blank"><strong>Vert</strong></a> &mdash; {{ _('index.descr:vert') }}</p>
+21
View File
@@ -0,0 +1,21 @@
{% extends 'base.tmpl' %}
{% block title %}О нас{% endblock %}
{% block content %}
<a href="{{ url_for('risdeveau.index') }}" class="block green">
<div class="header">
<img src="/static/icon/us/risdeveau.webp" class="icon"/>
Sweetbread
</div>
Главный админ, занимается почти всеми сервисами. Создал этот сайт
</a>
<div class="block orange disabled">
<div class="header">
<img src="/static/icon/us/chest.webp" class="icon"/>
Chest
</div>
Должна была помогать делать этот сайт
</div>
{% endblock %}
-17
View File
@@ -1,17 +0,0 @@
extends base.tmpl
block title
| О нас
block content
a.block.green(href="{{ url_for('risdeveau.index') }}")
.header
img.icon(src="/static/icon/us/risdeveau.webp")
| Sweetbread
| Главный админ, занимается почти всеми сервисами. Создал этот сайт
.block.orange.disabled
.header
img.icon(src="/static/icon/us/chest.webp")
| Chest
| Должна была помогать делать этот сайт
-1
View File
@@ -5,4 +5,3 @@ requests
APScheduler
musicbrainzngs
python-magic
pypugjs
+1 -1
View File
@@ -9,7 +9,7 @@ pkgs.mkShell {
python
python-magic
virtualenv
# pkgs.nodePackages.sass
pkgs.nodePackages.sass
];
shellHook = ''