「🎉」 init: working shitty script
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.direnv
|
||||
|
||||
.env
|
156
24h.ics
Normal file
156
24h.ics
Normal file
@ -0,0 +1,156 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Proton AG//ProtonCalendar 1.0.0//EN
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
X-WR-CALNAME:24h du Mans
|
||||
X-WR-CALDESC:
|
||||
X-WR-TIMEZONE:Europe/Paris
|
||||
REFRESH-INTERVAL;VALUE=DURATION:PT240M
|
||||
X-PUBLISHED-TTL:PT240M
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Paris
|
||||
LAST-MODIFIED:20250218T131521Z
|
||||
X-LIC-LOCATION:Europe/Paris
|
||||
BEGIN:DAYLIGHT
|
||||
TZNAME:CEST
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
DTSTART:19700329T020000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZNAME:CET
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
DTSTART:19701025T030000
|
||||
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-244d1309-86d5-42d5-8db3-e6e61f4bb67c
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Race
|
||||
DTSTART;TZID=Europe/Paris:20250614T160000
|
||||
DTEND;TZID=Europe/Paris:20250615T160000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-460cb9f4-cd83-4249-805c-212be3043944
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Qualifying - LMP2 & LMGT3
|
||||
DTSTART;TZID=Europe/Paris:20250611T184500
|
||||
DTEND;TZID=Europe/Paris:20250611T191500
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-c1f55045-3080-47aa-bf94-abf5d15a1ec0
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Warm-up
|
||||
DTSTART;TZID=Europe/Paris:20250614T120000
|
||||
DTEND;TZID=Europe/Paris:20250614T121500
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-80f4f074-58c0-456f-ba1b-589c0c6da159
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Free Practice 1
|
||||
DTSTART;TZID=Europe/Paris:20250611T140000
|
||||
DTEND;TZID=Europe/Paris:20250611T170000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-428f7889-c774-481f-b75c-b7db74799381
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Free Practice 4
|
||||
DTSTART;TZID=Europe/Paris:20250612T230000
|
||||
DTEND;TZID=Europe/Paris:20250613T000000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-fe0d6ec8-5491-4fed-8db4-be1070b796fe
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - HYPERPOLE 2 - HYPERCAR
|
||||
DTSTART;TZID=Europe/Paris:20250612T214000
|
||||
DTEND;TZID=Europe/Paris:20250612T215500
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-78a2d420-cf27-4527-911e-f8ac04204f23
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - HYPERPOLE 1 - HYPERCAR
|
||||
DTSTART;TZID=Europe/Paris:20250612T210500
|
||||
DTEND;TZID=Europe/Paris:20250612T212500
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-9a9dbd76-adb3-42e3-992c-2d0ef04dc909
|
||||
DTSTAMP:20250609T141021Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - HYPERPOLE 2 - LMP2 & LMGT3
|
||||
DTSTART;TZID=Europe/Paris:20250612T203500
|
||||
DTEND;TZID=Europe/Paris:20250612T205000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-f07a2dbe-8958-4e6d-948e-05c47cd71890
|
||||
DTSTAMP:20250609T141022Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - HYPERPOLE 1 - LMP2 & LMGT3
|
||||
DTSTART;TZID=Europe/Paris:20250612T200000
|
||||
DTEND;TZID=Europe/Paris:20250612T202000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-a7ec4975-04b1-44c8-8065-743e3cf6e7cb
|
||||
DTSTAMP:20250609T141022Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Free Practice 3
|
||||
DTSTART;TZID=Europe/Paris:20250612T144500
|
||||
DTEND;TZID=Europe/Paris:20250612T174500
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-fce906a9-4434-4adc-bcd6-0bb7669e0bb1
|
||||
DTSTAMP:20250609T141022Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Free Practice 2
|
||||
DTSTART;TZID=Europe/Paris:20250611T220000
|
||||
DTEND;TZID=Europe/Paris:20250612T000000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:sabre-vobject-8c32bb13-bb2e-4f29-9706-e4d03d8149d1
|
||||
DTSTAMP:20250609T141022Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Qualifying - Hypercar
|
||||
DTSTART;TZID=Europe/Paris:20250611T193000
|
||||
DTEND;TZID=Europe/Paris:20250611T200000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:AEf2LX8fa3lqe8dKTsDjPwmhvBip@proton.me
|
||||
DTSTAMP:20250609T141022Z
|
||||
SUMMARY:24 Hours of Le Mans 2025 - Eurosport 2
|
||||
DTSTART;TZID=Europe/Paris:20250610T193000
|
||||
DTEND;TZID=Europe/Paris:20250610T210000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:x14Vl7X2L6pSQBH2mt1IRuy-Vjjx@proton.me
|
||||
DTSTAMP:20250610T084743Z
|
||||
SUMMARY:test
|
||||
DTSTART;TZID=Europe/Paris:20250610T100000
|
||||
DTEND;TZID=Europe/Paris:20250610T120000
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
44
flake.lock
generated
Normal file
44
flake.lock
generated
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749285348,
|
||||
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pypresence": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1743073125,
|
||||
"narHash": "sha256-DjwDmQMbI9tV40TTe1CthhphoysKSFICrRhqijJjIAE=",
|
||||
"owner": "qwertyquerty",
|
||||
"repo": "pypresence",
|
||||
"rev": "4e882c36d0f800c016c15977243ac9a49177095a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "qwertyquerty",
|
||||
"repo": "pypresence",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pypresence": "pypresence"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
58
flake.nix
Normal file
58
flake.nix
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
pypresence.url = "github:qwertyquerty/pypresence";
|
||||
pypresence.flake = false;
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ self, nixpkgs, ... }:
|
||||
let
|
||||
supportedSystems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forEachSupportedSystem =
|
||||
f:
|
||||
nixpkgs.lib.genAttrs supportedSystems (
|
||||
system:
|
||||
f {
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
packages = forEachSupportedSystem (
|
||||
{ pkgs }:
|
||||
{
|
||||
default = pkgs.python313Packages.buildPythonPackage {
|
||||
pname = "pypresence";
|
||||
version = "4.4.0"; # Replace with the actual version or a placeholder
|
||||
format = "setuptools";
|
||||
src = inputs.pypresence;
|
||||
doCheck = false; # tests require internet connection
|
||||
pythonImportsCheck = [ "pypresence" ];
|
||||
};
|
||||
}
|
||||
);
|
||||
devShells = forEachSupportedSystem (
|
||||
{ pkgs }:
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
nixd
|
||||
nixfmt-rfc-style
|
||||
python313
|
||||
self.packages.${pkgs.system}.default
|
||||
python313Packages.icalendar
|
||||
python313Packages.pytz
|
||||
python313Packages.python-dotenv
|
||||
python313Packages.requests
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
93
rpc.py
Normal file
93
rpc.py
Normal file
@ -0,0 +1,93 @@
|
||||
from pypresence import Presence, ActivityType
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
import icalendar
|
||||
import pytz
|
||||
import requests
|
||||
from datetime import datetime, timezone
|
||||
import time
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Initialize PyPresence with your application ID
|
||||
client_id = os.getenv('DISCORD_APPLICATION_ID')
|
||||
ics_url = os.getenv('ICS_URL')
|
||||
|
||||
if not client_id or not ics_url:
|
||||
raise ValueError("issue in .env file")
|
||||
|
||||
RPC = Presence(client_id)
|
||||
|
||||
try:
|
||||
RPC.connect()
|
||||
except Exception as e:
|
||||
print(f"Failed to connect to Discord: {e}")
|
||||
exit(1)
|
||||
|
||||
def fetch_ics(url):
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
return response.content
|
||||
else:
|
||||
raise Exception("Failed to fetch the .ics file")
|
||||
|
||||
def parse_ics(ics_content):
|
||||
cal = icalendar.Calendar.from_ical(ics_content)
|
||||
events = []
|
||||
for component in cal.walk():
|
||||
if component.name == 'VEVENT':
|
||||
summary = component.get('summary')
|
||||
dtstart = component.get('dtstart').dt
|
||||
dtend = component.get('dtend').dt
|
||||
|
||||
# Convert datetime to timezone-aware if necessary
|
||||
if isinstance(dtstart, datetime) and dtstart.tzinfo is None:
|
||||
dtstart = pytz.utc.localize(dtstart)
|
||||
if isinstance(dtend, datetime) and dtend.tzinfo is None:
|
||||
dtend = pytz.utc.localize(dtend)
|
||||
|
||||
events.append({
|
||||
'summary': str(summary),
|
||||
'start': dtstart,
|
||||
'end': dtend
|
||||
})
|
||||
return events
|
||||
|
||||
def update_presence(event):
|
||||
now = datetime.now(timezone.utc)
|
||||
if event['start'] <= now <= event['end']:
|
||||
parts = event['summary'].split(' - ')
|
||||
if len(parts) == 2:
|
||||
state_part, details_part = parts
|
||||
else:
|
||||
state_part = event['summary']
|
||||
details_part = 'Event'
|
||||
|
||||
RPC.update(
|
||||
activity_type=ActivityType.WATCHING,
|
||||
details=details_part,
|
||||
state=state_part,
|
||||
large_image="favicon", # Replace with your image key
|
||||
large_text="Bangers incomming",
|
||||
start=int(event['start'].timestamp()),
|
||||
end=int(event['end'].timestamp())
|
||||
)
|
||||
else:
|
||||
RPC.clear()
|
||||
|
||||
print("Rich Presence is running. Press Ctrl+C to stop.")
|
||||
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
ics_content = fetch_ics(ics_url)
|
||||
events = parse_ics(ics_content)
|
||||
for event in events:
|
||||
update_presence(event)
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
time.sleep(60) # Update every minute
|
||||
except KeyboardInterrupt:
|
||||
print("Stopping Rich Presence...")
|
||||
finally:
|
||||
RPC.close()
|
Reference in New Issue
Block a user