├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── db-container-backup ├── db-container-backup.service ├── db-container-backup.sh └── db-container-backup.timer ├── raycast ├── __pycache__ │ └── repos.cpython-311.pyc ├── repos-check.py ├── repos-clean.py ├── repos-clone.py └── repos-list.py └── testing └── git-repos.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: christianlempa 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.env 2 | __pycache__/ 3 | *.pyc 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Christian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Christian's "Scripts" 2 | 3 | [![Welcome](https://cnd-prod-1.s3.us-west-004.backblazeb2.com/new-banner4-scaled-for-github.jpg)](https://youtu.be/apgp9egIKK8) 4 | 5 | **Hey, there!** 6 | 7 | **I’m Christian, and I’m passionate about creating educational tech content for IT Pros and Homelab nerds.** 8 | 9 | This Repository **Scripts** is my personal script collection. Here you'll find bash, and python scripts for various tools, and technologies. 10 | 11 | > :warning: Be aware, products can change over time. I do my best to keep up with the latest changes and releases, but please understand that this won’t always be the case. 12 | 13 | I created them as free resources to be used in your specific use cases. If you're searching for detailed, in-depth tutorials on some tools or technologies, check out my [YouTube Channel](https://www.youtube.com/@christianlempa). 14 | 15 | ## Contribution 16 | 17 | If you’d like to contribute to this project, reach out to me on social media or [Discord](https://christianlempa.de/discord), or create a pull request for the necessary changes. 18 | 19 | ## Other Resources 20 | 21 | - [Dotfiles](https://github.com/christianlempa/dotfiles) - My personal configuration files on macOS 22 | - [Boilerplates](https://github.com/christianlempa/boilerplates) - Templates for various projects like Docker, K8S, Ansible, etc 23 | - [Cheat-Sheets](https://github.com/christianlempa/cheat-sheets) - Command Reference for various tools and technologies 24 | - [Videos](https://github.com/christianlempa/videos) - Documentation and project files for all my video tutorials on YouTube 25 | - [Homelab](https://github.com/christianlempa/homelab) - This is my entire Homelab documentation, and configurations for infrastructure, applications, networking, and more. 26 | 27 | ## Support me 28 | 29 | Creating high-quality videos and valuable resources that are accessible to everyone, free of charge, is a huge challenge. With your contribution, I can dedicate more time and effort into the creation process, which ultimately enhances the quality of the content. So, all your support, by becoming a member, truly makes a significant impact on what I do. And you’ll also get some cool benefits and perks in return, as a recognition of your support. 30 | 31 | Remember, ***supporting me is entirely optional.*** Your choice to become a member or not won't change your access to my videos and resources. You are also welcome to reach out to me on Discord, if you have any questions or feedback. 32 | 33 | [https://www.patreon.com/christianlempa](https://www.patreon.com/christianlempa) 34 | -------------------------------------------------------------------------------- /db-container-backup/db-container-backup.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=DB Container Backup Script 3 | Wants=db-container-backup.timer 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=sh db-container-backup.sh 8 | User=xcad 9 | 10 | [Install] 11 | WantedBy=default.target -------------------------------------------------------------------------------- /db-container-backup/db-container-backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # DB Container Backup Script Template 4 | # --- 5 | # This backup script can be used to automatically backup databases in docker containers. 6 | # It currently supports mariadb, mysql and bitwardenrs containers. 7 | # 8 | 9 | DAYS=2 10 | BACKUPDIR=/home/xcad/backup 11 | 12 | 13 | # backup all mysql/mariadb containers 14 | 15 | CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | cut -d":" -f1) 16 | 17 | echo $CONTAINER 18 | 19 | if [ ! -d $BACKUPDIR ]; then 20 | mkdir -p $BACKUPDIR 21 | fi 22 | 23 | for i in $CONTAINER; do 24 | MYSQL_DATABASE=$(docker exec $i env | grep MYSQL_DATABASE |cut -d"=" -f2-) 25 | MYSQL_PWD=$(docker exec $i env | grep MYSQL_ROOT_PASSWORD |cut -d"=" -f2-) 26 | 27 | docker exec -e MYSQL_DATABASE=$MYSQL_DATABASE -e MYSQL_PWD=$MYSQL_PWD \ 28 | $i /usr/bin/mysqldump -u root $MYSQL_DATABASE \ 29 | | gzip > $BACKUPDIR/$i-$MYSQL_DATABASE-$(date +"%Y%m%d%H%M").sql.gz 30 | 31 | OLD_BACKUPS=$(ls -1 $BACKUPDIR/$i*.gz |wc -l) 32 | if [ $OLD_BACKUPS -gt $DAYS ]; then 33 | find $BACKUPDIR -name "$i*.gz" -daystart -mtime +$DAYS -delete 34 | fi 35 | done 36 | 37 | 38 | # bitwarden backup 39 | 40 | BITWARDEN_CONTAINERS=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'bitwardenrs' | cut -d":" -f1) 41 | 42 | for i in $BITWARDEN_CONTAINERS; do 43 | docker exec $i /usr/bin/sqlite3 data/db.sqlite3 .dump \ 44 | | gzip > $BACKUPDIR/$i-$(date +"%Y%m%d%H%M").sql.gz 45 | 46 | OLD_BITWARDEN_BACKUPS=$(ls -1 $BACKUPDIR/$i*.gz |wc -l) 47 | if [ $OLD_BITWARDEN_BACKUPS -gt $DAYS ]; then 48 | find $BACKUPDIR -name "$i*.gz" -daystart -mtime +$DAYS -delete 49 | fi 50 | done 51 | 52 | echo "$TIMESTAMP Backup for Databases completed" 53 | -------------------------------------------------------------------------------- /db-container-backup/db-container-backup.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=DB Container Backup Daily Job 3 | 4 | [Timer] 5 | OnCalendar=daily 6 | Persistent=true 7 | Unit=db-container-backup.service 8 | 9 | [Install] 10 | WantedBy=timers.target -------------------------------------------------------------------------------- /raycast/__pycache__/repos.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChristianLempa/scripts/3490e7488feae3b517b1fc59e6f68099dca06a3f/raycast/__pycache__/repos.cpython-311.pyc -------------------------------------------------------------------------------- /raycast/repos-check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Required parameters: 4 | # @raycast.schemaVersion 1 5 | # @raycast.title Check all my GitHub Repos 6 | # @raycast.mode compact 7 | 8 | # Optional parameters: 9 | # @raycast.icon https://avatars.githubusercontent.com/u/28359525?v=4 10 | 11 | # Documentation: 12 | # @raycast.author ChristianLempa 13 | # @raycast.authorURL https://raycast.com/ChristianLempa 14 | 15 | from dotenv import load_dotenv 16 | import os 17 | from pathlib import Path 18 | from github import Github 19 | import traceback 20 | 21 | 22 | load_dotenv() 23 | 24 | g = Github(os.getenv("GITHUB_TOKEN")) 25 | 26 | ignored_folders = [ 27 | '.git', 28 | '.DS_Store', 29 | '.obsidian', 30 | ] 31 | 32 | 33 | if __name__ == "__main__": 34 | try: 35 | repos = g.get_user('christianlempa').get_repos() 36 | missing_repos = [] 37 | 38 | if repos is not None: 39 | for repo in repos: 40 | # set repo path on local workstation 41 | repo_path = f'{ Path.home() }/projects/{repo.owner.login}/{repo.name}' 42 | 43 | # when repo is not existing 44 | if not os.path.exists(repo_path): 45 | missing_repos.append(repo.name) 46 | 47 | if len(missing_repos) > 0: 48 | print(f"You have {len(missing_repos)} missing repos. Consider cloning...") 49 | else: 50 | print("All repos are up to date.") 51 | else: 52 | print("Error: No repos found in organization") 53 | exit(1) 54 | 55 | except Exception: 56 | traceback.format_exc() 57 | exit(1) 58 | -------------------------------------------------------------------------------- /raycast/repos-clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Required parameters: 4 | # @raycast.schemaVersion 1 5 | # @raycast.title Clean all my orphaned GitHub Repos 6 | # @raycast.mode compact 7 | 8 | # Optional parameters: 9 | # @raycast.icon https://avatars.githubusercontent.com/u/28359525?v=4 10 | # @raycast.needsConfirmation true 11 | 12 | # Documentation: 13 | # @raycast.author ChristianLempa 14 | # @raycast.authorURL https://raycast.com/ChristianLempa 15 | 16 | from dotenv import load_dotenv 17 | import os 18 | from pathlib import Path 19 | from github import Github 20 | import traceback 21 | 22 | 23 | load_dotenv() 24 | 25 | g = Github(os.getenv("GITHUB_TOKEN")) 26 | 27 | ignored_folders = [ 28 | '.git', 29 | '.DS_Store', 30 | '.obsidian', 31 | ] 32 | 33 | 34 | if __name__ == "__main__": 35 | try: 36 | repos = g.get_user('christianlempa').get_repos() 37 | orphaned_repos = [] 38 | 39 | if repos is not None: 40 | 41 | # check all repos on local workstation 42 | # get all repos in projects folder 43 | for repo in os.listdir(f'{ Path.home() }/projects/christianlempa'): 44 | # check if repo is not in ignored folders 45 | if repo not in ignored_folders: 46 | # check if repo is not in github 47 | if repo not in [r.name for r in repos]: 48 | orphaned_repos.append(repo) 49 | 50 | if len(orphaned_repos) > 0: 51 | # delete oraphned repos 52 | for repo in orphaned_repos: 53 | os.system(f'rm -rf { Path.home() }/projects/christianlempa/{repo}') 54 | print(f"Deleted {len(orphaned_repos)} orphaned repos.") 55 | exit(0) 56 | else: 57 | print("No orphaned repos found.") 58 | exit(0) 59 | else: 60 | print("Error: No repos found in organization") 61 | exit(1) 62 | 63 | except Exception: 64 | traceback.format_exc() 65 | exit(1) 66 | -------------------------------------------------------------------------------- /raycast/repos-clone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Required parameters: 4 | # @raycast.schemaVersion 1 5 | # @raycast.title Clone all my GitHub Repos 6 | # @raycast.mode compact 7 | 8 | # Optional parameters: 9 | # @raycast.icon https://avatars.githubusercontent.com/u/28359525?v=4 10 | 11 | # Documentation: 12 | # @raycast.author ChristianLempa 13 | # @raycast.authorURL https://raycast.com/ChristianLempa 14 | 15 | from dotenv import load_dotenv 16 | import os 17 | from pathlib import Path 18 | from github import Github 19 | from git import Repo 20 | import traceback 21 | 22 | 23 | load_dotenv() 24 | 25 | g = Github(os.getenv("GITHUB_TOKEN")) 26 | 27 | ignored_folders = [ 28 | '.git', 29 | '.DS_Store', 30 | '.obsidian', 31 | ] 32 | 33 | 34 | if __name__ == "__main__": 35 | # Clone Repositories for christianlempa 36 | # https://docs.github.com/en/rest/reference/repos#list-organization-repositories 37 | # -- 38 | try: 39 | repos = g.get_user('christianlempa').get_repos() 40 | cloned_repos = [] 41 | 42 | if repos is not None: 43 | for repo in repos: 44 | # set repo path on local workstation 45 | repo_path = f'{ Path.home() }/projects/{repo.owner.login}/{repo.name}' 46 | 47 | # when repo is not existing 48 | if not os.path.exists(repo_path): 49 | # print(f" {repo['name']} - {repo['description']}") 50 | Repo.clone_from(repo.ssh_url, repo_path) 51 | cloned_repos.append(repo.name) 52 | 53 | if len(cloned_repos) > 0: 54 | print(f"cloned {len(cloned_repos)} repos.") 55 | else: 56 | print("all repos are already cloned.") 57 | else: 58 | print("error: no repos found in organization") 59 | exit(1) 60 | 61 | except Exception: 62 | traceback.format_exc() 63 | exit(1) 64 | -------------------------------------------------------------------------------- /raycast/repos-list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Required parameters: 4 | # @raycast.schemaVersion 1 5 | # @raycast.title List all my GitHub Repos 6 | # @raycast.mode fullOutput 7 | 8 | # Optional parameters: 9 | # @raycast.icon https://avatars.githubusercontent.com/u/28359525?v=4 10 | 11 | # Documentation: 12 | # @raycast.author ChristianLempa 13 | # @raycast.authorURL https://raycast.com/ChristianLempa 14 | 15 | from dotenv import load_dotenv 16 | import os 17 | from pathlib import Path 18 | from github import Github 19 | from git import Repo 20 | import traceback 21 | 22 | 23 | load_dotenv() 24 | 25 | g = Github(os.getenv("GITHUB_TOKEN")) 26 | 27 | ignored_folders = [ 28 | '.git', 29 | '.DS_Store', 30 | '.obsidian', 31 | ] 32 | 33 | if __name__ == "__main__": 34 | try: 35 | repos = g.get_user('christianlempa').get_repos() 36 | missing_repos = [] 37 | 38 | if repos is not None: 39 | for repo in repos: 40 | # set repo path on local workstation 41 | repo_path = f'{ Path.home() }/projects/{repo.owner.login}/{repo.name}' 42 | 43 | # when repo is not existing 44 | if not os.path.exists(repo_path): 45 | missing_repos.append(repo.name) 46 | print(f"\033[0;31m●\033[0m {repo.name} (missing)") 47 | else: 48 | current_repo = Repo(f"{ Path.home() }/projects/{repo.owner.login}/{repo.name}") 49 | 50 | # check if repo has untracked files 51 | if current_repo.untracked_files: 52 | print(f"\033[0;33m●\033[0m {repo.name} (untracked files)") 53 | elif current_repo.is_dirty(): 54 | print(f"\033[0;33m●\033[0m {repo.name} (dirty))") 55 | else: 56 | print(f"\033[0;32m●\033[0m {repo.name}") 57 | 58 | except Exception: 59 | traceback.format_exc() 60 | -------------------------------------------------------------------------------- /testing/git-repos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from dotenv import load_dotenv 4 | import os 5 | from pathlib import Path 6 | from github import Github 7 | from git import Repo 8 | 9 | 10 | load_dotenv() 11 | 12 | g = Github(os.getenv("GITHUB_TOKEN")) 13 | 14 | ignored_folders = [ 15 | '.git', 16 | '.DS_Store', 17 | '.obsidian', 18 | ] 19 | 20 | if __name__ == "__main__": 21 | try: 22 | repos = g.get_organization('clcreative').get_repos() 23 | 24 | if repos is not None: 25 | for repo in repos: 26 | # check if repo has updates 27 | # set repo path on local workstation 28 | repo_path = f'{ Path.home() }/projects/{repo.owner.login}/{repo.name}' 29 | 30 | current_repo = Repo(f"{ Path.home() }/projects/{repo.owner.login}/{repo.name}") 31 | 32 | # when repo is not existing 33 | if not os.path.exists(repo_path): 34 | print(f"\033[0;31m○\033[0m {repo.name}") 35 | else: 36 | # check if repo has untracked files 37 | if current_repo.untracked_files: 38 | print(f"\033[0;33m●\033[0m {repo.name} (untracked files)") 39 | elif current_repo.is_dirty(): 40 | print(f"\033[0;33m●\033[0m {repo.name} (dirty))") 41 | else: 42 | print(f"\033[0;32m●\033[0m {repo.name}") 43 | 44 | except Exception as e: 45 | print(f"error: {e}") 46 | --------------------------------------------------------------------------------