Compare commits
6 Commits
65d800685a
...
ab03903771
| Author | SHA1 | Date | |
|---|---|---|---|
| ab03903771 | |||
| a31105ff60 | |||
| 868c4c1880 | |||
| 3a59c38ad6 | |||
| 4be223390c | |||
| 21bd9c42bd |
329
.gitignore
vendored
329
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
.venv
|
||||
*.txt
|
||||
*temp/
|
||||
*.xlsx
|
||||
########################################################################################
|
||||
# project specific gitignore entries
|
||||
|
||||
@@ -175,3 +176,331 @@
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
|
||||
########################################################################################
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
# *.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bbl-SAVE-ERROR
|
||||
*.bcf
|
||||
*.bcf-SAVE-ERROR
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
*.rubbercache
|
||||
rubber.cache
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# attachfile2
|
||||
*.atfi
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
*.loc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glg-abr
|
||||
*.glo
|
||||
*.glo-abr
|
||||
*.gls
|
||||
*.gls-abr
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
# *.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hypdoc
|
||||
*.hd
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# latexindent will create succesive backup files by default
|
||||
#*.bak*
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.data.minted
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# spelling
|
||||
*.spell.bad
|
||||
*.spell.txt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# latexindent.pl
|
||||
*.bak[0-9]*
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
||||
BIN
LaTex/Ruderbeschriftung.pdf
Normal file
BIN
LaTex/Ruderbeschriftung.pdf
Normal file
Binary file not shown.
116
LaTex/Ruderbeschriftung.tex
Normal file
116
LaTex/Ruderbeschriftung.tex
Normal file
@@ -0,0 +1,116 @@
|
||||
\documentclass[a0,landscape]{sciposter}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{multicol}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{multirow}
|
||||
\usepackage{tabularx}
|
||||
|
||||
\usepackage[center]{titlesec} % Add this line
|
||||
|
||||
% Customize section font size
|
||||
\titleformat{\section}
|
||||
{\centering\normalfont\Huge\bfseries}{\thesection}{1em}{}
|
||||
|
||||
|
||||
|
||||
\title{Ruder Labeling System}
|
||||
\author{Georg Brantegger}
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% \maketitle
|
||||
|
||||
\begin{center}
|
||||
\begin{minipage}{0.9\textwidth}
|
||||
\section*{Ruder ID Format}
|
||||
% \begin{table}[]
|
||||
% \centering
|
||||
% \setlength{\tabcolsep}{40pt} % Adjust column spacing
|
||||
% \LARGE
|
||||
% \begin{tabular}{ccccccc}
|
||||
% \textbf{S1} & \textbf{S2} & \textbf{S3} & \textbf{S4} & \textbf{S5} & \textbf{S6} & \textbf{S7} \\
|
||||
% \textbf{Typ} & \textbf{Marke} & \textbf{Blatttyp} & \textbf{Anschaffungsjahr} & \textbf{Nummer} & \textbf{Seite} & \textbf{Rest}
|
||||
% \end{tabular}
|
||||
% \end{table}
|
||||
|
||||
\begin{table}[]
|
||||
\centering
|
||||
\setlength{\tabcolsep}{20pt}
|
||||
\LARGE
|
||||
\begin{tabular}{c@{ -- }c@{ -- }c@{ -- }c@{ -- }c@{ -- }c@{ -- }c}
|
||||
\textbf{S1} & \textbf{S2} & \textbf{S3} & \textbf{S4} & \textbf{S5} & \textbf{S6} & \textbf{S7} \\
|
||||
\textbf{Typ} & \textbf{Marke} & \textbf{Blatttyp} & \textbf{Anschaffungsjahr} & \textbf{Nummer} & \textbf{Seite} & \textbf{Rest}
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
\section*{Erklärung der Segmente}
|
||||
|
||||
\begin{table}[h!]
|
||||
\centering
|
||||
\setlength{\tabcolsep}{40pt} % Adjust column spacing
|
||||
\LARGE
|
||||
\begin{tabular}{ccccc} % Remove extra space on the sides
|
||||
\toprule
|
||||
\textbf{Segmentnummer} & \textbf{Segmentname} & \textbf{Anzahl Stellen} & \textbf{Wert} & \textbf{Langtext} \\
|
||||
\midrule
|
||||
\multirow{2}{*}{\textbf{S1}} &
|
||||
\multirow{2}{*}{\textbf{Typ}} &
|
||||
\multirow{2}{*}{1}
|
||||
& S: & Skull \\
|
||||
& & & R: & Riemen \\
|
||||
\midrule
|
||||
\multirow{4}{*}{\textbf{S2}} &
|
||||
\multirow{4}{*}{\textbf{Marke}} &
|
||||
\multirow{4}{*}{2}
|
||||
& C2: & Concept 2 \\
|
||||
& & & Cr: & Croker \\
|
||||
& & & Em: & Empacher \\
|
||||
& & & Sw: & Swift Racing \\
|
||||
\midrule
|
||||
\multirow{2}{*}{\textbf{S3}} &
|
||||
\multirow{2}{*}{\textbf{Blatttyp}} &
|
||||
\multirow{2}{*}{1}
|
||||
& M: & Macon \\
|
||||
& & & H: & Hacke \\
|
||||
\midrule
|
||||
\multirow{4}{*}{\textbf{S4}} &
|
||||
\multirow{4}{*}{\textbf{Anschaffungsjahr}} &
|
||||
\multirow{4}{*}{4}
|
||||
& 19XX: & irgendwann vor 2000 \\
|
||||
& & & 200X: & zwischen 2000-2009 \\
|
||||
& & & 201X: & zwischen 2010-2019 \\
|
||||
& & & 202X: & zwischen 2020-2025 \\
|
||||
\midrule
|
||||
\multirow{1}{*}{\textbf{S5}} &
|
||||
\multirow{1}{*}{\textbf{Nummer}} &
|
||||
\multirow{1}{*}{2}
|
||||
& 00-99: & fortlaufend, wenn \textbf{S1}-\textbf{S4} gleich \\
|
||||
\midrule
|
||||
\multirow{2}{*}{\textbf{S6}} &
|
||||
\multirow{2}{*}{\textbf{Seite}} &
|
||||
\multirow{2}{*}{1}
|
||||
& B: & Backbord \\
|
||||
& & & S: & Steuerbord \\
|
||||
\midrule
|
||||
\multirow{2}{*}{\textbf{S7}} &
|
||||
\multirow{2}{*}{\textbf{Rest}} &
|
||||
\multirow{2}{*}{\textless \ 5}
|
||||
& sk: & Concept2 Skinny Schaft \\
|
||||
& & & \dots & \dots \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
|
||||
\section*{Beispiele}
|
||||
\begin{center}
|
||||
\Huge
|
||||
\textbf{S-C2-H-201X-99-B-sk}
|
||||
\end{center}
|
||||
\end{minipage}
|
||||
\end{center}
|
||||
|
||||
\end{document}
|
||||
|
||||
291
Nextcloud Contact Infos/convert_athletes.ipynb
Normal file
291
Nextcloud Contact Infos/convert_athletes.ipynb
Normal file
@@ -0,0 +1,291 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1293f184",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import os\n",
|
||||
"import requests\n",
|
||||
"import urllib\n",
|
||||
"import io\n",
|
||||
"import base64\n",
|
||||
"\n",
|
||||
"from matplotlib import pyplot as plt\n",
|
||||
"import matplotlib.image as mpimg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2946897b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for file in os.listdir('temp'):\n",
|
||||
" os.remove(os.path.join('temp',file))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb57d754",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"user = \"Georg Brantegger\"\n",
|
||||
"with open('app_pw.txt','r') as f:\n",
|
||||
" app_pw = f.readline()\n",
|
||||
"\n",
|
||||
"base_url = \"https://nextcloud.karnelegger.eu/remote.php/webdav\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "234e6a70",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"folders = [\"Forms\",\"6 - Kontaktdatenerhebung RV Villach\",\"Ergebnisse CSV\"]\n",
|
||||
"folder_string = '/'.join([urllib.parse.quote(folder) for folder in folders])\n",
|
||||
"filename_csv = \"Kontaktdatenerhebung RV Villach (Antworten).csv\"\n",
|
||||
"\n",
|
||||
"url_csv = '/'.join([base_url,folder_string,urllib.parse.quote(filename_csv)])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"r = requests.get(url_csv, auth=(user, app_pw))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a74d9129",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df = pd.read_csv(io.StringIO(r.text),usecols=[3,4,5,6,7,8],header=0,names=['Vorname','Nachname','rower','Jahrgang','Foto','Telefonnummer'])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "28dbb7e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fc8568d6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def extract_tel(row,col):\n",
|
||||
" # remove the first ' and all whitespaces within number\n",
|
||||
"\n",
|
||||
" tel = str(row[col])\n",
|
||||
"\n",
|
||||
" replace_dict = {\"'\":'',' ':''}\n",
|
||||
" \n",
|
||||
" for key, value in replace_dict.items():\n",
|
||||
" tel = tel.replace(key,value)\n",
|
||||
"\n",
|
||||
" # handle people who don't know how country codes work\n",
|
||||
" if tel[0] == '0':\n",
|
||||
" tel = '+43'+tel[1:]\n",
|
||||
" if tel[0] == '6':\n",
|
||||
" tel = '+43'+tel\n",
|
||||
" if tel[0:4] == '+430':\n",
|
||||
" tel = '+43'+tel[4:]\n",
|
||||
" if tel[0:3] == '+49':\n",
|
||||
" tel = '+43'+tel[3:]\n",
|
||||
" if tel[0:2] == '43':\n",
|
||||
" tel = '+43'+tel[2:]\n",
|
||||
" if tel[0:2] == '+6':\n",
|
||||
" tel = '+43'+tel[1:]\n",
|
||||
" \n",
|
||||
" return tel\n",
|
||||
"\n",
|
||||
"def evaluate_rower(row,col='rower'):\n",
|
||||
" if row[col] == 'Ruder:in':\n",
|
||||
" return True\n",
|
||||
" else:\n",
|
||||
" return False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "68eaead1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e868df47",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df['Vorname'] = df['Vorname'].str.strip()\n",
|
||||
"df['Nachname'] = df['Nachname'].str.strip()\n",
|
||||
"df['rower'] = df.apply(evaluate_rower,axis=1,args=('rower',))\n",
|
||||
"df['Telefonnummer'] = df.apply(extract_tel,axis=1,args=('Telefonnummer',))\n",
|
||||
"df['Foto'] = df['Foto'].str.replace(' ','-').fillna('-')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "614ac3b3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "df2c876c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_photo_for_row(row):\n",
|
||||
"\n",
|
||||
" filename = row['Foto']\n",
|
||||
"\n",
|
||||
" if filename != '-':\n",
|
||||
"\n",
|
||||
" found_photo = False\n",
|
||||
" i = 30\n",
|
||||
" while found_photo is False:\n",
|
||||
" print(f\"trying folder {i}\")\n",
|
||||
" folders = [\"Forms\",\"6 - Kontaktdatenerhebung RV Villach\",f\"{i}\",\"23 - photo_name\"]\n",
|
||||
" folder_string = '/'.join([urllib.parse.quote(folder) for folder in folders])\n",
|
||||
" filename_photo = urllib.parse.quote(filename)\n",
|
||||
"\n",
|
||||
" url_photo = '/'.join([base_url,folder_string,urllib.parse.quote(filename_photo)])\n",
|
||||
"\n",
|
||||
" r = requests.get(url_photo, auth=(user, app_pw))\n",
|
||||
" if r.status_code != 200:\n",
|
||||
" i+=1\n",
|
||||
" if i > 200:\n",
|
||||
" break\n",
|
||||
" continue\n",
|
||||
" else:\n",
|
||||
" photo_bytes = r.content\n",
|
||||
" found_photo = True\n",
|
||||
" photo_b64 = base64.b64encode(photo_bytes).decode(\"utf-8\")\n",
|
||||
" \n",
|
||||
" i = base64.b64decode(photo_b64)\n",
|
||||
" i = io.BytesIO(i)\n",
|
||||
" i = mpimg.imread(i, format='JPG')\n",
|
||||
"\n",
|
||||
" plt.imshow(i, interpolation='nearest')\n",
|
||||
" plt.show()\n",
|
||||
"\n",
|
||||
" return photo_b64\n",
|
||||
" \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8c9db8d6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def convert_rows_to_vcf(row):\n",
|
||||
" # Map CSV columns to vCard fields\n",
|
||||
" first_name = row['Vorname']\n",
|
||||
" last_name = row['Nachname']\n",
|
||||
" phone = row['Telefonnummer']\n",
|
||||
" year = row['Jahrgang']\n",
|
||||
" rower = row['rower']\n",
|
||||
" cat = 'RVV Athlet:innen' if rower is True else 'RVV Eltern'\n",
|
||||
" address_book = 'rv-villach-athletinnen' if rower is True else 'rv-villach-eltern'\n",
|
||||
" photo_b64 = get_photo_for_row(row)\n",
|
||||
"\n",
|
||||
" lines = [\n",
|
||||
" \"BEGIN:VCARD\",\n",
|
||||
" \"VERSION:3.0\",\n",
|
||||
" f\"FN:{last_name} {first_name}\",\n",
|
||||
" f\"N:{last_name};{first_name};;;\",\n",
|
||||
" f\"CATEGORIES:{cat}\",\n",
|
||||
" f\"TEL;TYPE=CELL:{phone}\"]\n",
|
||||
" \n",
|
||||
" if rower is True:\n",
|
||||
" lines.append(f'NOTE:JG {year}')\n",
|
||||
"\n",
|
||||
" if photo_b64:\n",
|
||||
" lines.append(f\"PHOTO;ENCODING=b;TYPE=JPEG:{photo_b64}\")\n",
|
||||
"\n",
|
||||
" lines.append(\"END:VCARD\")\n",
|
||||
"\n",
|
||||
" vcard_content = \"\\n\".join(lines)\n",
|
||||
"\n",
|
||||
" # Save to file\n",
|
||||
" filename = f\"{last_name}_{first_name}.vcf\".replace(\" \", \"_\")\n",
|
||||
" with open(os.path.join('temp', filename), 'w') as f:\n",
|
||||
" f.write(vcard_content)\n",
|
||||
"\n",
|
||||
" # upload file to correct address book\n",
|
||||
"\n",
|
||||
" base_url_contacts = \"https://nextcloud.karnelegger.eu/remote.php/dav/addressbooks/users/Georg%20Brantegger/\"\n",
|
||||
" url = base_url_contacts + address_book + '/' + filename\n",
|
||||
"\n",
|
||||
" with open(f'temp/{filename}', \"rb\") as f:\n",
|
||||
" r = requests.put(\n",
|
||||
" url,\n",
|
||||
" data=f,\n",
|
||||
" auth=(user, app_pw),\n",
|
||||
" headers={\"Content-Type\": \"text/vcard\"}\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" print(filename, r.status_code)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "61659f5b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df.apply(convert_rows_to_vcf,axis=1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
383
Nextcloud Contact Infos/convert_athletes_V1.ipynb
Normal file
383
Nextcloud Contact Infos/convert_athletes_V1.ipynb
Normal file
@@ -0,0 +1,383 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1293f184",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import os\n",
|
||||
"import requests\n",
|
||||
"import urllib\n",
|
||||
"import io\n",
|
||||
"import base64\n",
|
||||
"\n",
|
||||
"from matplotlib import pyplot as plt\n",
|
||||
"import matplotlib.image as mpimg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2946897b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for file in os.listdir('temp'):\n",
|
||||
" os.remove(os.path.join('temp',file))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb57d754",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"user = \"Georg Brantegger\"\n",
|
||||
"with open('app_pw.txt','r') as f:\n",
|
||||
" app_pw = f.readline()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"base_url_csv = \"https://nextcloud.karnelegger.eu/remote.php/webdav\"\n",
|
||||
"folders = [\"Forms\",\"2 - Kontaktdatenerhebung Ruder-innen RV Villach\",\"Ergebnisse CSV\"]\n",
|
||||
"folder_string = '/'.join([urllib.parse.quote(folder) for folder in folders])\n",
|
||||
"filename_csv = \"Kontaktdatenerhebung Ruder-innen RV Villach (Antworten).csv\"\n",
|
||||
"\n",
|
||||
"url_csv = '/'.join([base_url_csv,folder_string,urllib.parse.quote(filename_csv)])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"r = requests.get(url_csv, auth=(user, app_pw))\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "543d5103",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def extract_tel(row,col):\n",
|
||||
" # remove the first ' and all whitespaces within number\n",
|
||||
"\n",
|
||||
" tel = str(row[col])\n",
|
||||
"\n",
|
||||
" replace_dict = {\"'\":'',' ':''}\n",
|
||||
" \n",
|
||||
" for key, value in replace_dict.items():\n",
|
||||
" tel = tel.replace(key,value)\n",
|
||||
"\n",
|
||||
" # handle people who don't know how country codes work\n",
|
||||
" if tel[0] == '0':\n",
|
||||
" tel = '+43'+tel[1:]\n",
|
||||
" if tel[0] == '6':\n",
|
||||
" tel = '+43'+tel\n",
|
||||
" if tel[0:4] == '+430':\n",
|
||||
" tel = '+43'+tel[4:]\n",
|
||||
" if tel[0:3] == '+49':\n",
|
||||
" tel = '+43'+tel[3:]\n",
|
||||
" if tel[0:2] == '43':\n",
|
||||
" tel = '+43'+tel[2:]\n",
|
||||
" if tel[0:2] == '+6':\n",
|
||||
" tel = '+43'+tel[1:]\n",
|
||||
" \n",
|
||||
" return tel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a74d9129",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df = pd.read_csv(io.StringIO(r.text))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2ba590c1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"name_replacement_dict = {',':'',\n",
|
||||
" 'Christoph Spath-Glantschnig': 'Spath-Glantschnig Christoph',\n",
|
||||
" 'Felix Assmann-Hafenscherer': 'Assmann-Hafenscherer Felix',\n",
|
||||
" 'Elias Assmann': 'Assmann Elias',\n",
|
||||
" 'Bernadette Assmann ': 'Assmann Bernadette',\n",
|
||||
" 'Tropea Giuseppe Manfredi': 'Tropea Manfredi Giuseppe',\n",
|
||||
" 'Sabrina': 'Bellotti Sabrina',\n",
|
||||
" 'Ich bin 18': None,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"df['Mein Name ist:'] = df['Mein Name ist:'].replace(name_replacement_dict,regex=True).str.strip()\n",
|
||||
"df['Name Kontaktperson/Kind 1'] = df['Name Kontaktperson/Kind 1'].replace(name_replacement_dict,regex=True).str.strip()\n",
|
||||
"df['Name Kontaktperson/Kind 2'] = df['Name Kontaktperson/Kind 2'].replace(name_replacement_dict,regex=True).str.strip()\n",
|
||||
"df['Name Kontaktperson/Kind 3'] = df['Name Kontaktperson/Kind 3'].replace(name_replacement_dict,regex=True).str.strip()\n",
|
||||
"\n",
|
||||
"df['Meine Telefonnummer ist:'] = df.apply(extract_tel,axis=1,args=('Meine Telefonnummer ist:',))\n",
|
||||
"df['Telefonnummer Kontaktperson 1'] = df.apply(extract_tel,axis=1,args=('Telefonnummer Kontaktperson 1',))\n",
|
||||
"df['Telefonnummer Kontaktperson 2'] = df.apply(extract_tel,axis=1,args=('Telefonnummer Kontaktperson 2',))\n",
|
||||
"df['Telefonnummer Kontaktperson 3'] = df.apply(extract_tel,axis=1,args=('Telefonnummer Kontaktperson 3',))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3b664ba7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "58057da5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# manually fix_Felix row\n",
|
||||
"row = df.loc[df['Mein Name ist:'] == 'Hafenscherer Rita',:]\n",
|
||||
"row['Mein Name ist:'] = 'Assmann-Hafenscherer Felix'\n",
|
||||
"row['Ich bin:'] = 'Ruder:in'\n",
|
||||
"row['Meine Telefonnummer ist:'] = '+4367764409018'\n",
|
||||
"row['Name Kontaktperson/Kind 1'] = 'Hafenscherer Rita'\n",
|
||||
"row['Telefonnummer Kontaktperson 1'] = '+436509623400'\n",
|
||||
"df.loc[df['Mein Name ist:'] == 'Hafenscherer Rita',:] = row"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "562a911b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fc8568d6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rowers_columns = ['Mein Name ist:',\n",
|
||||
" 'Mein Jahrgang ',\n",
|
||||
" 'Lade ein nettes Selfy hoch!',\n",
|
||||
" 'Meine Telefonnummer ist:',\n",
|
||||
" 'Name Kontaktperson/Kind 1',\n",
|
||||
" 'Telefonnummer Kontaktperson 1',\n",
|
||||
" 'Name Kontaktperson/Kind 2',\n",
|
||||
" 'Telefonnummer Kontaktperson 2',\n",
|
||||
" 'Name Kontaktperson/Kind 3',\n",
|
||||
" 'Telefonnummer Kontaktperson 3']\n",
|
||||
"\n",
|
||||
"rowers_dict = {key: [] for key in rowers_columns}\n",
|
||||
"\n",
|
||||
"parents_columns = ['Mein Name ist:',\n",
|
||||
" 'Lade ein nettes Selfy hoch!',\n",
|
||||
" 'Meine Telefonnummer ist:',\n",
|
||||
" 'Name Kontaktperson/Kind 1',\n",
|
||||
" 'Telefonnummer Kontaktperson 1',\n",
|
||||
" 'Name Kontaktperson/Kind 2',\n",
|
||||
" 'Telefonnummer Kontaktperson 2',\n",
|
||||
" 'Name Kontaktperson/Kind 3',\n",
|
||||
" 'Telefonnummer Kontaktperson 3']\n",
|
||||
"\n",
|
||||
"parents_dict = {key: [] for key in parents_columns}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2d44beb8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for _,row in df.iterrows():\n",
|
||||
" if (row['Ich bin:'] == 'Ruder:in') | (row['Mein Name ist:']=='Assmann-Hafenscherer Felix'):\n",
|
||||
" for col in rowers_columns:\n",
|
||||
" rowers_dict[col].append(row[col])\n",
|
||||
" \n",
|
||||
" elif row['Ich bin:'] == 'Elternteil/erwachsene Ansprechperson':\n",
|
||||
" for col in parents_columns:\n",
|
||||
" parents_dict[col].append(row[col])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "118dd1a7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rowers_df = pd.DataFrame(rowers_dict)\n",
|
||||
"parents_df = pd.DataFrame(parents_dict)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f1b7dd6b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rowers_df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f1e3f59d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parents_df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "df2c876c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# def get_photo_for_row(row):\n",
|
||||
"\n",
|
||||
"# filename = row['Foto']\n",
|
||||
"\n",
|
||||
"# found_photo = False\n",
|
||||
"# i = 0\n",
|
||||
"# while found_photo is False:\n",
|
||||
"# print(f\"trying folder {i}\")\n",
|
||||
"# base_url_photo = \"https://nextcloud.karnelegger.eu/remote.php/webdav\"\n",
|
||||
"# folders = [\"Forms\",\"4 - Kontaktdatenerhebung Trainerteam\",f\"{i}\",\"19 - Foto\"]\n",
|
||||
"# folder_string = '/'.join([urllib.parse.quote(folder) for folder in folders])\n",
|
||||
"# filename_photo = urllib.parse.quote(filename)\n",
|
||||
"\n",
|
||||
"# url_photo = '/'.join([base_url_photo,folder_string,urllib.parse.quote(filename_photo)])\n",
|
||||
"\n",
|
||||
"# r = requests.get(url_photo, auth=(user, app_pw))\n",
|
||||
"# if r.status_code != 200:\n",
|
||||
"# i+=1\n",
|
||||
"# if i > 100:\n",
|
||||
"# break\n",
|
||||
"# continue\n",
|
||||
"# else:\n",
|
||||
"# photo_bytes = r.content\n",
|
||||
"# found_photo = True\n",
|
||||
"# photo_b64 = base64.b64encode(photo_bytes).decode(\"utf-8\")\n",
|
||||
" \n",
|
||||
"# i = base64.b64decode(photo_b64)\n",
|
||||
"# i = io.BytesIO(i)\n",
|
||||
"# i = mpimg.imread(i, format='JPG')\n",
|
||||
"\n",
|
||||
"# plt.imshow(i, interpolation='nearest')\n",
|
||||
"# plt.show()\n",
|
||||
"\n",
|
||||
"# return photo_b64\n",
|
||||
" \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8c9db8d6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# def convert_rows_to_vcf(row):\n",
|
||||
"# # Map CSV columns to vCard fields\n",
|
||||
"# first_name = row['Vorname']\n",
|
||||
"# last_name = row['Nachname']\n",
|
||||
"# phone = row['Telefonnummer']\n",
|
||||
"# org = 'Ruderverein Villach von 1881'\n",
|
||||
"# photo_b64 = get_photo_for_row(row)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"# lines = [\n",
|
||||
"# \"BEGIN:VCARD\",\n",
|
||||
"# \"VERSION:3.0\",\n",
|
||||
"# f\"FN:{first_name} {last_name}\",\n",
|
||||
"# f\"N:{last_name};{first_name};;;\",\n",
|
||||
"# f\"ORG:{org}\",\n",
|
||||
"# f\"TEL;TYPE=CELL:{phone}\"]\n",
|
||||
"\n",
|
||||
"# if photo_b64:\n",
|
||||
"# lines.append(f\"PHOTO;ENCODING=b;TYPE=JPEG:{photo_b64}\")\n",
|
||||
"\n",
|
||||
"# lines.append(\"END:VCARD\")\n",
|
||||
"\n",
|
||||
"# vcard_content = \"\\n\".join(lines)\n",
|
||||
"\n",
|
||||
"# # Save to file\n",
|
||||
"# filename = f\"{last_name}_{first_name}.vcf\".replace(\" \", \"_\")\n",
|
||||
"# with open(os.path.join('temp', filename), 'w') as f:\n",
|
||||
"# f.write(vcard_content)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "61659f5b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# df.apply(convert_rows_to_vcf,axis=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "37b2a51b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# base_url = \"https://nextcloud.karnelegger.eu/remote.php/dav/addressbooks/users/Georg%20Brantegger/rv-villach-trainer/\"\n",
|
||||
"\n",
|
||||
"# for vcf_file in os.listdir('temp'):\n",
|
||||
"\n",
|
||||
"# url = base_url + vcf_file\n",
|
||||
"\n",
|
||||
"# with open(f'temp/{vcf_file}', \"rb\") as f:\n",
|
||||
"# r = requests.put(\n",
|
||||
"# url,\n",
|
||||
"# data=f,\n",
|
||||
"# auth=(user, app_pw),\n",
|
||||
"# headers={\"Content-Type\": \"text/vcard\"}\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# print(vcf_file, r.status_code)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -136,6 +136,7 @@
|
||||
" first_name = row['Vorname']\n",
|
||||
" last_name = row['Nachname']\n",
|
||||
" phone = row['Telefonnummer']\n",
|
||||
" cat = 'RVV Trainer:innen'\n",
|
||||
" org = 'Ruderverein Villach von 1881'\n",
|
||||
" photo_b64 = get_photo_for_row(row)\n",
|
||||
" \n",
|
||||
@@ -143,8 +144,9 @@
|
||||
" lines = [\n",
|
||||
" \"BEGIN:VCARD\",\n",
|
||||
" \"VERSION:3.0\",\n",
|
||||
" f\"FN:{first_name} {last_name}\",\n",
|
||||
" f\"FN:{last_name} {first_name}\",\n",
|
||||
" f\"N:{last_name};{first_name};;;\",\n",
|
||||
" f\"CATEGORIES:{cat}\",\n",
|
||||
" f\"ORG:{org}\",\n",
|
||||
" f\"TEL;TYPE=CELL:{phone}\"]\n",
|
||||
"\n",
|
||||
|
||||
184
Nextcloud Video Files/create_video_folder_for_all_contacts.ipynb
Normal file
184
Nextcloud Video Files/create_video_folder_for_all_contacts.ipynb
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "152c4ce0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import requests"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "041b0ab6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# --- Configuration ---\n",
|
||||
"NEXTCLOUD_URL = \"https://nextcloud.karnelegger.eu\"\n",
|
||||
"USERNAME = \"Georg Brantegger\"\n",
|
||||
"with open('app_pw.txt','r') as f:\n",
|
||||
" APP_PASSWORD = f.readline()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Modern Nextcloud WebDAV endpoint format:\n",
|
||||
"WEBDAV_BASE_URL = f\"{NEXTCLOUD_URL}/remote.php/dav/files/{USERNAME}/Shared/Ruderverein/Videoanalyse\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "19ec4c3e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def create_nextcloud_folder(folder_url):\n",
|
||||
" \"\"\"Sends a MKCOL request to Nextcloud to create a folder.\"\"\"\n",
|
||||
" response = requests.request(\"MKCOL\", folder_url, auth=(USERNAME, APP_PASSWORD))\n",
|
||||
" \n",
|
||||
" if response.status_code in [201, 207]:\n",
|
||||
" print(f\"✅ Success: Created folder at {folder_url}\")\n",
|
||||
" elif response.status_code == 405:\n",
|
||||
" # WebDAV returns 405 Method Not Allowed if the folder already exists\n",
|
||||
" print(f\"⏩ Skipped: Folder already exists at {folder_url}\")\n",
|
||||
" elif response.status_code == 409:\n",
|
||||
" print(f\"❌ Error: Parent folder doesn't exist for {folder_url}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"❌ Error {response.status_code}: Could not create folder.\")\n",
|
||||
" print(response.text)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "b4c04efb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import requests\n",
|
||||
"import vobject\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# This is the \"URL slug\" of your address book. \n",
|
||||
"# Usually, if you name it \"Athletes\", the slug is \"athletes\" (lowercase).\n",
|
||||
"# You can find the exact name by going to Contacts -> Settings (bottom left) -> \n",
|
||||
"# Click the 3 dots next to your address book -> \"Copy link\". \n",
|
||||
"# The link will end with /addressbooks/users/username/THIS_PART/\n",
|
||||
"ADDRESSBOOK_NAME = \"rv-villach-athletinnen\" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# The ?export parameter tells Nextcloud to dump the whole address book at once\n",
|
||||
"CARDDAV_URL = f\"{NEXTCLOUD_URL}/remote.php/dav/addressbooks/users/{USERNAME}/{ADDRESSBOOK_NAME}/?export\"\n",
|
||||
"\n",
|
||||
"def get_athlete_names():\n",
|
||||
" print(f\"Fetching contacts from the '{ADDRESSBOOK_NAME}' address book...\")\n",
|
||||
" response = requests.get(CARDDAV_URL, auth=(USERNAME, APP_PASSWORD))\n",
|
||||
" \n",
|
||||
" if response.status_code != 200:\n",
|
||||
" print(f\"❌ Error {response.status_code}: Could not fetch address book.\")\n",
|
||||
" print(\"Check your URL, credentials, and make sure the ADDRESSBOOK_NAME is exactly right.\")\n",
|
||||
" return []\n",
|
||||
"\n",
|
||||
" vcf_data = response.text\n",
|
||||
" athletes = []\n",
|
||||
"\n",
|
||||
" # Parse the multi-contact VCF data\n",
|
||||
" for vcard in vobject.readComponents(vcf_data):\n",
|
||||
" # The 'n' property in a vCard holds the structured Name (First, Last, etc.)\n",
|
||||
" if hasattr(vcard, 'n'):\n",
|
||||
" first_name = vcard.n.value.given\n",
|
||||
" last_name = vcard.n.value.family\n",
|
||||
" \n",
|
||||
" # Combine them. The .strip() helps if someone only has a first or last name\n",
|
||||
" full_name = f\"{last_name} {first_name}\".strip()\n",
|
||||
" \n",
|
||||
" if full_name:\n",
|
||||
" athletes.append(full_name)\n",
|
||||
" \n",
|
||||
" # Fallback just in case a contact only has a \"Formatted Name\" (fn) saved\n",
|
||||
" elif hasattr(vcard, 'fn'):\n",
|
||||
" athletes.append(vcard.fn.value)\n",
|
||||
" \n",
|
||||
" return athletes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "306aef25",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"⏩ Skipped: Folder already exists at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse\n",
|
||||
"Fetching contacts from the 'rv-villach-athletinnen' address book...\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Aufegger%20Tobias\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Praschnig%20Flora\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Buchacher%20Eva\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Gigacher%20Olivia\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/McGrath%20Samuel\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Magdalena%20Truppe\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Yang%20Ruien\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Yang%20Xiaoen\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Kofler%20Hannah\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Tropea%20Manfredi\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Spath-Glantschnig%20%20Christoph\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Acerbi%20Sofia\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Aufegger%20Emilia\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Henriks%20Alva\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Tscherne%20Tobias\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Pressinger%20Laurin\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Bodner%20Emma\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Jop%20Nicolas\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Assmann-Hafenscherer%20Felix\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Henriks%20Konstantin\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Loidl%20Lieselotte\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Poga%C4%8Dar%20Anamary\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Polessnig%20Valentina\n",
|
||||
"✅ Success: Created folder at https://nextcloud.karnelegger.eu/remote.php/dav/files/Georg Brantegger/Shared/Ruderverein/Videoanalyse/Paulik%20Elena\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 1. Create the main base folder first (just in case it doesn't exist)\n",
|
||||
"create_nextcloud_folder(WEBDAV_BASE_URL)\n",
|
||||
"\n",
|
||||
"# 2. Loop through your athletes and create a folder for each\n",
|
||||
"for athlete in get_athlete_names():\n",
|
||||
" # It's usually good practice to replace spaces with underscores for web URLs, \n",
|
||||
" # but Nextcloud handles spaces fine if we format the URL correctly.\n",
|
||||
" # We use requests.utils.quote to properly encode spaces and special characters.\n",
|
||||
" safe_folder_name = requests.utils.quote(athlete)\n",
|
||||
" athlete_folder_url = f\"{WEBDAV_BASE_URL}/{safe_folder_name}\"\n",
|
||||
" \n",
|
||||
" create_nextcloud_folder(athlete_folder_url)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
251
Trainingspläne/create_template.ipynb
Normal file
251
Trainingspläne/create_template.ipynb
Normal file
@@ -0,0 +1,251 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "efde98a5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import datetime as dt\n",
|
||||
"import openpyxl.styles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "8e84cb92",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_week_boundary(target_date, boundary='first'):\n",
|
||||
" \"\"\"\n",
|
||||
" Returns the Monday (first) or Sunday (last) of the week for a given date.\n",
|
||||
" \n",
|
||||
" :param target_date: datetime object\n",
|
||||
" :param boundary: 'first' or 'last'\n",
|
||||
" :return: datetime object\n",
|
||||
" \"\"\"\n",
|
||||
" # .weekday() returns 0 for Monday, 6 for Sunday\n",
|
||||
" days_since_monday = target_date.weekday()\n",
|
||||
" \n",
|
||||
" if boundary == 'first':\n",
|
||||
" return target_date - dt.timedelta(days=days_since_monday)\n",
|
||||
" elif boundary == 'last':\n",
|
||||
" days_until_sunday = 6 - days_since_monday\n",
|
||||
" return target_date + dt.timedelta(days=days_until_sunday)\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\"Boundary must be 'first' or 'last'\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "7a9ce99f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"year = 2026\n",
|
||||
"\n",
|
||||
"date_index = pd.date_range(get_week_boundary(dt.datetime(year,1,1),'first'),get_week_boundary(dt.datetime(year,12,31),'last'),freq='1D')\n",
|
||||
"\n",
|
||||
"columns = ['KW','date','weekday','location','trainer','meetup_time','start_time','warmup','main','cooldown','post_workout','approx_end']\n",
|
||||
"columns = columns + [f'padding_{i}' for i in range(5)]\n",
|
||||
"header_names = ['KW','Datum','Tag','Ort','Trainer:in','Treffpunkt','Trainingsbeginn','Warm-Up','Programm','Cool-Down','Post-Workout','Trainingsende']\n",
|
||||
"header_names = header_names + ['' for i in range(5)]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"df = pd.DataFrame(index=date_index,columns=columns)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "7be00de3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"weekday_dict_short = {0: 'Mo',\n",
|
||||
" 1: 'Di',\n",
|
||||
" 2: 'Mi',\n",
|
||||
" 3: 'Do',\n",
|
||||
" 4: 'Fr',\n",
|
||||
" 5: 'Sa',\n",
|
||||
" 6: 'So'}\n",
|
||||
"\n",
|
||||
"weekday_dict_long = {0: 'Montag',\n",
|
||||
" 1: 'Dienstag',\n",
|
||||
" 2: 'Mittwoch',\n",
|
||||
" 3: 'Donnerstag',\n",
|
||||
" 4: 'Freitag',\n",
|
||||
" 5: 'Samstag',\n",
|
||||
" 6: 'Sonntag'}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "3f25dd5f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df['KW'] = df.index.isocalendar().week\n",
|
||||
"df['date'] = df.index.strftime('%d.%m.%Y')\n",
|
||||
"df['weekday'] = df.index.weekday\n",
|
||||
"df['weekday'] = df['weekday'].replace(weekday_dict_short)\n",
|
||||
"df['location'] = 'RVV'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "2b98908c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_month_slice(df,month_number):\n",
|
||||
"\n",
|
||||
" week_numbers_of_month = df.loc[df.index.month==month_number,'KW'].unique()\n",
|
||||
"\n",
|
||||
" if month_number == 1:\n",
|
||||
" week_numbers_of_month = [week_number if (week_number < 6) else None for week_number in week_numbers_of_month]\n",
|
||||
" elif month_number == 12:\n",
|
||||
" week_numbers_of_month = [week_number if (week_number > 40) else None for week_number in week_numbers_of_month]\n",
|
||||
"\n",
|
||||
" df_slice = df.loc[df['KW'].isin(week_numbers_of_month),:]\n",
|
||||
" return df_slice"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "69339931",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def highlight_weekends(row):\n",
|
||||
" # .weekday() > 4 means Saturday (5) or Sunday (6)\n",
|
||||
" if row.name.weekday() > 4:\n",
|
||||
" return ['background-color: #ffcccc'] * len(row) # Light red/pink\n",
|
||||
" return [''] * len(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "379682df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def format_rows(row):\n",
|
||||
" # .weekday() > 4 means Saturday (5) or Sunday (6)\n",
|
||||
" if row.name.weekday() == 0:\n",
|
||||
" bg_style = 'background-color: #D1D1D1'\n",
|
||||
" border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 1:\n",
|
||||
" bg_style = ''\n",
|
||||
" border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 2:\n",
|
||||
" bg_style = 'background-color: #D1D1D1'\n",
|
||||
" border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 3:\n",
|
||||
" bg_style = ''\n",
|
||||
" border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 4:\n",
|
||||
" bg_style = 'background-color: #D1D1D1'\n",
|
||||
" border_style = 'border-bottom: 2pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 5:\n",
|
||||
" bg_style = 'background-color: ##C5D9F1'\n",
|
||||
" border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n",
|
||||
" elif row.name.weekday() == 6:\n",
|
||||
" bg_style = 'background-color: ##C5D9F1'\n",
|
||||
" border_style = 'border-bottom: 3pt solid black; border-left: 1pt solid black'\n",
|
||||
"\n",
|
||||
" # Combine them (separated by semicolon)\n",
|
||||
" combined = f\"{bg_style}; {border_style}\"\n",
|
||||
" return [combined] * len(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "ae3bf250",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"months = range(1,12+1,1)\n",
|
||||
"file_name = f\"Trainingsplan_{year}.xlsx\"\n",
|
||||
"\n",
|
||||
"with pd.ExcelWriter(file_name, engine='openpyxl') as writer:\n",
|
||||
" for month in months:\n",
|
||||
" df_month = get_month_slice(df, month)\n",
|
||||
" \n",
|
||||
" # 1 format the cells\n",
|
||||
" \n",
|
||||
" # 1.1 format the rows (background color and borders)\n",
|
||||
" styled_df = df_month.style.apply(format_rows, axis=1)\n",
|
||||
" \n",
|
||||
" # 1.2 center all cells\n",
|
||||
" styled_df = styled_df.set_properties(**{'text-align': 'center'})\n",
|
||||
" \n",
|
||||
" # 2 Write to xlsx\n",
|
||||
" styled_df.to_excel(writer, sheet_name=f\"{month}_{year}\",index=False,header=header_names)\n",
|
||||
"\n",
|
||||
" # 3 after writing, change other formats\n",
|
||||
" # --- Access the openpyxl worksheet object ---\n",
|
||||
" worksheet = writer.sheets[f\"{month}_{year}\"]\n",
|
||||
"\n",
|
||||
" # 3.1 set the widths\n",
|
||||
" worksheet.column_dimensions['A'].width = 18*0.35\n",
|
||||
" worksheet.column_dimensions['B'].width = 18*0.89\n",
|
||||
" worksheet.column_dimensions['C'].width = 18*0.35\n",
|
||||
" worksheet.column_dimensions['D'].width = 18*0.40\n",
|
||||
" worksheet.column_dimensions['E'].width = 18*0.73\n",
|
||||
" worksheet.column_dimensions['F'].width = 18*0.81\n",
|
||||
" worksheet.column_dimensions['G'].width = 18*1.05\n",
|
||||
" worksheet.column_dimensions['H'].width = 18*0.76\n",
|
||||
" worksheet.column_dimensions['I'].width = 18*2.50\n",
|
||||
" worksheet.column_dimensions['J'].width = 18*0.76\n",
|
||||
" worksheet.column_dimensions['K'].width = 18*1.05\n",
|
||||
" worksheet.column_dimensions['L'].width = 18*1.05\n",
|
||||
"\n",
|
||||
" # 3.2 format the header\n",
|
||||
" # Define a bold, larger font\n",
|
||||
" header_font = openpyxl.styles.Font(name='Arial', size=12, bold=True, color=\"000000\")\n",
|
||||
" \n",
|
||||
" # Iterate through the first row (Header)\n",
|
||||
" # worksheet[1] returns all cells in the first row\n",
|
||||
" for cell in worksheet[1]:\n",
|
||||
" cell.font = header_font\n",
|
||||
" cell.alignment = openpyxl.styles.Alignment(horizontal='center', vertical='center')\n",
|
||||
" cell.border = openpyxl.styles.Border(bottom=openpyxl.styles.Side(border_style='medium', color='000000'))\n",
|
||||
"\n",
|
||||
" # 3.3 freeze the first row\n",
|
||||
" worksheet.freeze_panes = 'A2' "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -15,8 +15,13 @@ def get_list_of_packages_to_load():
|
||||
packages.append('numpy')
|
||||
packages.append('pandas')
|
||||
packages.append('pyarrow')
|
||||
packages.append('odfpy')
|
||||
packages.append('fsspec')
|
||||
# packages.append('openpyxl')
|
||||
packages.append('vobject')
|
||||
packages.append('requests')
|
||||
packages.append('openpyxl')
|
||||
packages.append('jinja2') # for styling
|
||||
|
||||
# packages.append('matplotlib')
|
||||
# packages.append('pyqt5')
|
||||
# packages.append('tirex-ts')
|
||||
@@ -25,7 +30,6 @@ def get_list_of_packages_to_load():
|
||||
# packages.append('pyinstaller')
|
||||
# packages.append('oracledb')
|
||||
# packages.append('sqlalchemy')
|
||||
packages.append('requests')
|
||||
# packages.append('requests_negotiate_sspi ')
|
||||
# packages.append('ldap3')
|
||||
# packages.append('mplcursors')
|
||||
|
||||
Reference in New Issue
Block a user