I started off the year not expecting to do much programming. Compared to some months in 2021, I barely programmed, but I did end up programming much more than I expected. Let’s take a look at what I worked on in the first sixth of the year.
Python Programs
End of Year Video Games Helper
Coming off of last year in which I finally used Python to pull my last.fm data and create graphs, I decided to do the same for my End of Year Video Games blog post. I haven’t posted the code to Github, but here it is:
"""Go through Let's Play directories and sum up total time per video. Assumes directory per game."""from datetime import time, timedeltafrom pathlib import Pathfrom rich import printfrom pymediainfo import MediaInfodef sum_times(directory: Path) -> tuple:"""Sum the duration of all videos in this directory.Return a tuple with the name of the game and the total time.Assumption: names of directory is name of game."""video_files = [item for item in directory.iterdir() if not item.is_dir()]total_length = timedelta(0, 0, 0, 0)for video_file in video_files:video_info = MediaInfo.parse(str(video_file))for track in video_info.tracks:if track.track_type == "Video":video_dict = track.to_data()video_length = video_dict['other_duration'][4]split_video_length = video_length.split(":")total_length += timedelta(hours=int(split_video_length[0]), minutes=int(split_video_length[1]),seconds=int(split_video_length[2]))return directory.parts[-1], total_lengthif __name__ == ' __main__':starting_directory = Path("my_videos/")gather_subdirectories = [item for item in starting_directory.iterdir() if item.is_dir()]games_and_lengths = []annual_total = timedelta(0, 0, 0, 0)for subdirectory in gather_subdirectories:game, length = sum_times(subdirectory)annual_total += lengthgames_and_lengths.append((game, length))sorted_games_and_lengths = sorted(games_and_lengths, key=lambda game_length: game_length[1], reverse=True)with open("games_and_times.txt", 'w') as file:for position, game_tuple in enumerate(sorted_games_and_lengths):file.write(f"{position+1}. {game_tuple[0]} ({game_tuple[1]}): \n")file.write(f"Total Time for 2021: {annual_total}")"""Go through Let's Play directories and sum up total time per video. Assumes directory per game.""" from datetime import time, timedelta from pathlib import Path from rich import print from pymediainfo import MediaInfo def sum_times(directory: Path) -> tuple: """Sum the duration of all videos in this directory. Return a tuple with the name of the game and the total time. Assumption: names of directory is name of game. """ video_files = [item for item in directory.iterdir() if not item.is_dir()] total_length = timedelta(0, 0, 0, 0) for video_file in video_files: video_info = MediaInfo.parse(str(video_file)) for track in video_info.tracks: if track.track_type == "Video": video_dict = track.to_data() video_length = video_dict['other_duration'][4] split_video_length = video_length.split(":") total_length += timedelta(hours=int(split_video_length[0]), minutes=int(split_video_length[1]), seconds=int(split_video_length[2])) return directory.parts[-1], total_length if __name__ == ' __main__': starting_directory = Path("my_videos/") gather_subdirectories = [item for item in starting_directory.iterdir() if item.is_dir()] games_and_lengths = [] annual_total = timedelta(0, 0, 0, 0) for subdirectory in gather_subdirectories: game, length = sum_times(subdirectory) annual_total += length games_and_lengths.append((game, length)) sorted_games_and_lengths = sorted(games_and_lengths, key=lambda game_length: game_length[1], reverse=True) with open("games_and_times.txt", 'w') as file: for position, game_tuple in enumerate(sorted_games_and_lengths): file.write(f"{position+1}. {game_tuple[0]} ({game_tuple[1]}): \n") file.write(f"Total Time for 2021: {annual_total}")"""Go through Let's Play directories and sum up total time per video. Assumes directory per game.""" from datetime import time, timedelta from pathlib import Path from rich import print from pymediainfo import MediaInfo def sum_times(directory: Path) -> tuple: """Sum the duration of all videos in this directory. Return a tuple with the name of the game and the total time. Assumption: names of directory is name of game. """ video_files = [item for item in directory.iterdir() if not item.is_dir()] total_length = timedelta(0, 0, 0, 0) for video_file in video_files: video_info = MediaInfo.parse(str(video_file)) for track in video_info.tracks: if track.track_type == "Video": video_dict = track.to_data() video_length = video_dict['other_duration'][4] split_video_length = video_length.split(":") total_length += timedelta(hours=int(split_video_length[0]), minutes=int(split_video_length[1]), seconds=int(split_video_length[2])) return directory.parts[-1], total_length if __name__ == ' __main__': starting_directory = Path("my_videos/") gather_subdirectories = [item for item in starting_directory.iterdir() if item.is_dir()] games_and_lengths = [] annual_total = timedelta(0, 0, 0, 0) for subdirectory in gather_subdirectories: game, length = sum_times(subdirectory) annual_total += length games_and_lengths.append((game, length)) sorted_games_and_lengths = sorted(games_and_lengths, key=lambda game_length: game_length[1], reverse=True) with open("games_and_times.txt", 'w') as file: for position, game_tuple in enumerate(sorted_games_and_lengths): file.write(f"{position+1}. {game_tuple[0]} ({game_tuple[1]}): \n") file.write(f"Total Time for 2021: {annual_total}")
Enter fullscreen mode Exit fullscreen mode
It worked very well and saved me hours of time going through each video to sum up the total play time. This is, as I have said, the best use of programming.
Extra Life Donation Tracker v7.1.0
This year was the first year in which I didn’t make an initial donation when I signed up for Extra Life. Turns out there were a few issues I’d never realized existed for someone who wanted to use my program without any donations whatsoever. I fixed those issues and cut a new release.
Prophecy Practicum (Django)
I’ve previously mentioned the project I created for my friend to help reduce the barrier on one aspect of his spiritual practice. He had asked me to work on a few quality of life issues. After I knocked those out (for a 5.0 release), I was very motivated to keep going. The 6.0 release was about beautification (mostly with CSS) to make the site look a bit more modern. I ended up using the Bulma CSS framework (apparently CSS has reached that level of modernization to where folks use frameworks instead of manually creating CSS). Of course, in the course of creating and testing the CSS changes, I found a few more places to improve the code to make it better for the users. It made me incredibly happy to make things work better for my friend and the other users.
Python Learning
As I continued to read through Data Visualization with Python and Javascript, I started to gain an understanding of CSS (which helped above when I worked on the Django project). I’m reading the book on the side as I work on other stuff so it’s slow going, but I hope to use it to visualize my last.fm data going forward.
I also started going through the Talk Python Pycharm class. I’ve been using Pycharm for a year or two now, but I’m learning so many new features that are already helping to make my programming work a lot easier – especially around refactoring.
Advent of Code
I did one tiny bit of Advent of Code in February – I implemented Advent of Code 2016 Day 5 in Go. This allowed me to learn about creating MD5 hashes in Go as well as practice functions and remind myself of the Go syntax since it’d been a couple months since I last coded in Go.
// Solution to Advent of Code Day 05 -- Do You Want to Play a Gamepackage mainimport ("crypto/md5""encoding/hex""fmt""strconv")// createHash returns a md5 hash of a stringfunc createHash(textToHash string) string {hash := md5.Sum([]byte(textToHash))return hex.EncodeToString(hash[:])}// validateHash returns true if this is a hash with 5 leading 0sfunc validateHash(hashToCheck string) bool {for position, char := range hashToCheck {if position < 5 {if string(char) == "0" {continue} else {break}}if position == 5 {return true}}return false}// createDoorOnePassword takes in the input for this question and produces the passwordfunc createDoorOnePassword(aocInput string) string {var password stringnumericalSuffix := 0for len(password) < 8 {testHash := createHash(aocInput + strconv.Itoa(numericalSuffix))//fmt.Println(testHash)if validateHash(testHash) {password += string([]rune(testHash)[5])}numericalSuffix++}return password}// createDoorTwoPassword takes in the aoc input and uses the new rules to produce the door passwordfunc createDoorTwoPassword(aocInput string) string {var password [8]runevar locationCheck [8]boolnumericalSuffix := 0for locationCheck[0] == false || locationCheck[1] == false || locationCheck[2] == false || locationCheck[3] == false || locationCheck[4] == false || locationCheck[5] == false || locationCheck[6] == false || locationCheck[7] == false {testHash := createHash(aocInput + strconv.Itoa(numericalSuffix))if validateHash(testHash) {probableLocation := string([]rune(testHash)[5])if probableLocation == "0" || probableLocation == "1" || probableLocation == "2" || probableLocation == "3" || probableLocation == "4" || probableLocation == "5" || probableLocation == "6" || probableLocation == "7" {location, _ := strconv.Atoi(probableLocation)character := []rune(testHash)[6]if locationCheck[location] == false {locationCheck[location] = truepassword[location] = character}}}numericalSuffix++}return string(password[:])}func main() {aocInput := "ugkcyxxp"doorOnePassword := createDoorOnePassword(aocInput)fmt.Printf("The password to door #1 is %s\n", doorOnePassword)doorTwoPassword := createDoorTwoPassword(aocInput)fmt.Printf("The password to door #2 is %s", doorTwoPassword)}// Solution to Advent of Code Day 05 -- Do You Want to Play a Game package main import ( "crypto/md5" "encoding/hex" "fmt" "strconv" ) // createHash returns a md5 hash of a string func createHash(textToHash string) string { hash := md5.Sum([]byte(textToHash)) return hex.EncodeToString(hash[:]) } // validateHash returns true if this is a hash with 5 leading 0s func validateHash(hashToCheck string) bool { for position, char := range hashToCheck { if position < 5 { if string(char) == "0" { continue } else { break } } if position == 5 { return true } } return false } // createDoorOnePassword takes in the input for this question and produces the password func createDoorOnePassword(aocInput string) string { var password string numericalSuffix := 0 for len(password) < 8 { testHash := createHash(aocInput + strconv.Itoa(numericalSuffix)) //fmt.Println(testHash) if validateHash(testHash) { password += string([]rune(testHash)[5]) } numericalSuffix++ } return password } // createDoorTwoPassword takes in the aoc input and uses the new rules to produce the door password func createDoorTwoPassword(aocInput string) string { var password [8]rune var locationCheck [8]bool numericalSuffix := 0 for locationCheck[0] == false || locationCheck[1] == false || locationCheck[2] == false || locationCheck[3] == false || locationCheck[4] == false || locationCheck[5] == false || locationCheck[6] == false || locationCheck[7] == false { testHash := createHash(aocInput + strconv.Itoa(numericalSuffix)) if validateHash(testHash) { probableLocation := string([]rune(testHash)[5]) if probableLocation == "0" || probableLocation == "1" || probableLocation == "2" || probableLocation == "3" || probableLocation == "4" || probableLocation == "5" || probableLocation == "6" || probableLocation == "7" { location, _ := strconv.Atoi(probableLocation) character := []rune(testHash)[6] if locationCheck[location] == false { locationCheck[location] = true password[location] = character } } } numericalSuffix++ } return string(password[:]) } func main() { aocInput := "ugkcyxxp" doorOnePassword := createDoorOnePassword(aocInput) fmt.Printf("The password to door #1 is %s\n", doorOnePassword) doorTwoPassword := createDoorTwoPassword(aocInput) fmt.Printf("The password to door #2 is %s", doorTwoPassword) }// Solution to Advent of Code Day 05 -- Do You Want to Play a Game package main import ( "crypto/md5" "encoding/hex" "fmt" "strconv" ) // createHash returns a md5 hash of a string func createHash(textToHash string) string { hash := md5.Sum([]byte(textToHash)) return hex.EncodeToString(hash[:]) } // validateHash returns true if this is a hash with 5 leading 0s func validateHash(hashToCheck string) bool { for position, char := range hashToCheck { if position < 5 { if string(char) == "0" { continue } else { break } } if position == 5 { return true } } return false } // createDoorOnePassword takes in the input for this question and produces the password func createDoorOnePassword(aocInput string) string { var password string numericalSuffix := 0 for len(password) < 8 { testHash := createHash(aocInput + strconv.Itoa(numericalSuffix)) //fmt.Println(testHash) if validateHash(testHash) { password += string([]rune(testHash)[5]) } numericalSuffix++ } return password } // createDoorTwoPassword takes in the aoc input and uses the new rules to produce the door password func createDoorTwoPassword(aocInput string) string { var password [8]rune var locationCheck [8]bool numericalSuffix := 0 for locationCheck[0] == false || locationCheck[1] == false || locationCheck[2] == false || locationCheck[3] == false || locationCheck[4] == false || locationCheck[5] == false || locationCheck[6] == false || locationCheck[7] == false { testHash := createHash(aocInput + strconv.Itoa(numericalSuffix)) if validateHash(testHash) { probableLocation := string([]rune(testHash)[5]) if probableLocation == "0" || probableLocation == "1" || probableLocation == "2" || probableLocation == "3" || probableLocation == "4" || probableLocation == "5" || probableLocation == "6" || probableLocation == "7" { location, _ := strconv.Atoi(probableLocation) character := []rune(testHash)[6] if locationCheck[location] == false { locationCheck[location] = true password[location] = character } } } numericalSuffix++ } return string(password[:]) } func main() { aocInput := "ugkcyxxp" doorOnePassword := createDoorOnePassword(aocInput) fmt.Printf("The password to door #1 is %s\n", doorOnePassword) doorTwoPassword := createDoorTwoPassword(aocInput) fmt.Printf("The password to door #2 is %s", doorTwoPassword) }
Enter fullscreen mode Exit fullscreen mode
暂无评论内容