 First off, thanks everyone for joining us. What my goal is today is to show how to contribute to an open source project, even if you can't work directly with the developer of that project, basically just how to get in with that community. And you guys know, if you've seen anything on my channel before, that we talk a lot about Surugi Linux, and it is surugilinux.org over here. So, Surugi Linux is a Linux distribution, and it has a lot of different tools inside of it, and some of those tools are developed by the Surugi Linux developers themselves, and some of them are developed by the community. Almost all of them are open source and freely available in terms of the tools. And so if you wanted to contribute to the community, an easy way to do that is just find a bug or find something that's not quite working right in your tools, and yeah, just try to make it better is essentially what we're going for here. So let's switch on over to Surugi Linux running. And I've already mounted up. I don't know if you guys have seen the last video I did, but I was using EWF mount to mount an EWF image, and then once we had that EWF image mounted, then we can mount the partition inside of it and start working with the partition directly. So I've basically done exactly the same thing. And in this slash mnt slash c drive, if I do ls, we can see all of the files in the suspect partition. So this is the suspect's c partition. This is mounted read only. So we know it's the c drive or the root directory because we have things like the swap file sys, and page file, everything like that. Okay. So what I wanted to do with this, imagine that you want to go through and search all of the data, all of the files inside this c drive. What we could do with Linux tools is just something like find and then grep, and let's say we want to find something with a JPEG extension. So let me try a JPG because I know they're in there. Okay. So JPG extension, we can just do a quick find and we'll look for the file names inside this c drive. Okay. So we found this generic English one dot JPG. So maybe we can process something with that. Okay. Well, in the Sorugi Linux, we have the applications and then under Sorugi, it has a bunch of different utilities already set up for us. And one of the utilities that I was interested in using is this picture analysis. And then if you scroll down, there's search screenshots, search screenshots. So if we open that up, we get a command line tool. I don't mind that one. We get a command line tool in the background. And basically the way that we use search screenshots, it's a Python script as a help menu. This is the help menu. We give it an input directory. We give it an output directory. Width, height, and pixels. And then it kind of explains what that is. But basically what we're interested in is the input directory, output directory, and then search screenshots will tell us if an image that it finds looks to be a screenshot. And it does it by the width and height of the image itself. Okay. And then of course, the image pixels, how many pixels it has could also be an indicator. So you can actually set the width and height yourself if you have some sort of custom device, but search screenshots already has a few sizes already built in. All right. So if we do, let's go back to our other, our C drive. If we do search screenshots.py, let's do input directory. And I'm just going to give it the current directory and the output directory I'll say I'll just put it on the desktop because I know I have right access to it. If I press enter, we get an error. Okay. One error is that it's a read-only file system. And this tends to happen a lot. So I'm inside the mounted read-only file system right now. I gave an output directory of the desktop, but the program still wants to write a folder into the current directory. Okay. And I'll just tell you, search screenshots has a lot of other problems. Basically, the way, the only way you can use it is if you have a single folder with all of the screenshots inside that folder. All the images dumped into one folder with no subdirectories. Okay. So if you do an extraction and all of your, you know, images from your suspect system is in that single folder, then you can use search screenshots to try to filter them out very quickly and do all that. But that's kind of a pain, right? So instead we have a suspect device, mounted read-only. I want to be able to scan that entire device and then pull out images that look like screenshots. But we already have the basis for a program that does that here. It just doesn't have the ability to do, for example, recursion and go into subdirectories. And some other things. So what I want to do today is show how we can start to modify or work on these programs that don't really have the features that we want, how we can add them actually pretty easily. Okay. So I'm going to go to... The first thing we can do in Linux is do which search screenshots. And then that will tell us the location of the screenshots, search screenshots pie program. Yep. So then now we know the location. Let's go ahead and copy that. And then if I just do, I'm just going to use nano for now, paste in that file. And then we can see it's just a normal Python program and it has, for example, the date that it was last updated. So it's getting kind of old. It doesn't mean it doesn't work. It's fine. It just is lacking some features. It's the MIT license, which is good because that means we can edit it. If you run into a program that has a... For every program you're working with, just check the license and make sure that you actually have edit and redistribution rights. If you don't, that'll be a problem. Don't edit it unless you actually have permission to do it. Notice you can talk to the developer of that program and try to get permission if you don't already have it or it's not an open license. So the license is provided as is. Liable for any claim, damages, connection software. So we do need to check if we can actually redistribute this, but I think under MIT we can. So let's go ahead and check that real quick. Does anyone in chat know? I'm pretty sure we can redistribute with the MIT license. So to deal with the software without restriction, including without limitation and rights usage, modify, merge, publish, distribute. So that's what we're wanting here, is the ability to be able to modify it and potentially redistribute it. And today we're going to try to distribute. All right. So okay, we know our license is okay. First, if you're familiar with Python, we have a bunch of imports. And then we have destination file directory is essentially creating a destination directory with the date and time. We're getting a string for that. And then it looks like we're just immediately making the directory. And this is a bit of a problem where as soon as we start the program, whether we're doing a help menu or whether we have a file path to actually work with, we still are creating a folder. So we're already going in and making a directory. And that's probably why we're having an error directly at the beginning whenever I try to run the program. So that could be something that we're interested in changing. Next, we have arg parse. There's a question in the chat. How do you create a list to sort files by type? Are you creating a list in Python or are you in an Excel spreadsheet? Like this program is a Python program, but it will create an Excel spreadsheet as an output. And then potentially you could sort by extension. Or are you just using Linux command line tools? Okay, answer in the chat and I will come back to it. So right now we have arg parse. And arg parse is just taking arguments from the command line and then using them. And basically we're just putting the input output directories. Next, we're creating our output directory. Notice we didn't get to that point before because we had that path exist make directory destination file directory was created immediately. So this is definitely something that we should take care of. And then the output directory seems to be a different variable or idea or directory from where we're saving all the files. Okay, we have some global variables created. Okay, and then we're creating... Sorry, it's not an Excel spreadsheet. It's a CSV file. So file name CSV, write, and then we have the file name width height, MD5 hash, SHA1 hash. So we know that they're creating two different hashes what looks like probably all of the files. We'll come back to that. But maybe it's all the screenshots or all the files. I'm not sure yet. And then we have images, OS, Lister. So this is the input directory. So it's listing everything from the input directory. And this is where we first start to get our file list that we're going to work with. Okay, so then once we get our image list, we basically have a for loop over every image in that list. Now remember that is in a single directory, not subdirectories or anything like that. So we might be able to just change the Lister's argument to be recursive. And then that would go into every subdirectory. And then that could solve some of our problem here. Right, and then we open the image, image file. We get the width using the image library from Python. And then we just print the width and height. And then we have an if check about the width and height. And that looks like maybe the custom image width and height that we give it if we do an argument. And then we have another if statement where the width and height is hard coded. So we have the width image 720 height image 1440. And they say moto g6 play PXT 1922. So for specifically a moto phone, I think we have a width and a height for screenshots that are normally created. So that's hard coded in there. And then we're doing image show. So the image, I guess probably pops up. And then we save the image to the output directory, print the width and height, hash the file, and then write all of that data to the CSV file. And then we sleep and then we hide the image. Okay, so there's kind of a lot going on here. But I can already see that we have a lot of redundant code. Okay, so for the first if statement, we have the hash functions. For the second file size, we have the hash functions again. And then we have an L if, which is another just essentially case statement with a different size for an ASUS Z017D. And then we basically have all of the same code again. So whenever you see the same code being used over and over again with only a couple variables being changed, that's a really good candidate for a loop. Okay, so I don't really see any functions, like custom functions written in here, but I am seeing a lot of LF statements and then a lot of the same code over and over again. Okay, so there was a post, there was a post by the Seguri Linux team, and they basically said that their team is full and for security reasons and a lot of other reasons, they're not taking anyone else onto the team in terms of development, but it is an open source project. So we still can contribute to it. It just means that we can't be on the main team who rolls the distribution. But we can definitely update this program and it looks like there's a couple places where we can make it more efficient if we want to. I thought this would be an interesting case to look at. So the first thing I'm going to do is go into GitHub because if we're sharing data, especially if we're going to make it open source ourselves, the easiest way to share is GitHub. And I'm going to create a new repository and I'm going to call it search screenshots. Okay, and then this is the Regi Linux search screenshots utility. And the reason that I'm creating a new repository versus an old versus just using one that already exists is because I didn't find any Regi Linux repository. I don't think they actually have a repository. I think they keep it all within themselves. From the chat, the intention is to report the media files found in a forensic image, all image files, all video files, all audio files, regardless of the length. Okay, and then you want to sort them by extension. What I would do from Antonio from the chat, what I would likely do if I wanted to get a list of all of the files from a directory. Actually, we can do that here. It's bigger for you guys. So in Mount C drive, in Mount C drive, I have all of my, all of the suspects files in Windows, they're C drive. If you do find, for example, you can find by type or you can find by extension. So for example, he's looking for, yeah. Okay, again, it's still like JPEG. If you do grep I, you don't care about the case. And then find dot looks from the current directory and then all of the subdirectories. We are piping that into JPEG. So then that'll find everything with JPEGs. And basically what I would do is use grep with regular expressions to state all of the file extensions that I was interested in. Now what you'll find though is that it might not be just a file extension. So I would list out JPEG or what's another one you're looking at? BMP. I don't know if there'll be any BMPs here, but I think I have to use eGrep for that. I haven't done a chain of names for a long time. There we go. So you can see at the beginning here eGrep basically uses regular expressions. And I did eGrep-i because I don't care about the case. And then in quotes, I have my JPEG extension that I'm looking for. And then the pipe here means or and then I have BMP for the next extension that I'm looking for. So if you know the extensions that you're looking for, something like this will give you a list. But here we have like a BMP was found first and then I have a file that's not actually a JPEG. It's a DLL. And then I have JPEGs at the foot. So I would dump all of these into a file. I don't know on my desktop. And just call it multimedia, something like that. Multimedia list. Okay. Now from that multimedia list, let's see what's in there. I'll just get basically the full path of where I was running find from and then a filtered list of all of what looks like multimedia files. I could do the regular expression a little bit better to get rid of like these DLLs, for example. But that's pretty much how I would do it dump all of that into a list. And then if you want to sort, there's a couple of different tools where you can just sort directly based on extension, or I would dump all of the extensions into another column, like if it was a CSV sort that column and then display full path. So there's a couple of different ways to do it. It just depends on are you writing a Python script? Are you writing a bash script? Are you doing everything from command line? And what's the goal of having it like by file type? Does it matter? Also, while you're doing this, you can also use the file command. So for example, we have this zero dot JPG in Linux. If we use the file command, we can see we can find information about. It has a space. Anyway, from using the file command, we can see information about the file header, which might be a more reliable way than the file extension, because the file extension can be changed. I never use, for example, dot txt files in Linux. I always actually most of the time I don't put extensions with text files. I just have a file. But if you have the file command, you can look at the file by file header and then kind of understand what it is a little bit easier. Okay. So going back to GitHub. Yeah. So I didn't find anything much about Sorugi Linux like on GitHub. And I don't think they have an open repository, which is why. There's a lot of things called Sorugi, but it's not what we're looking for. So in that case, since I couldn't find a repository where the main creators are already maintaining it, if you think they're not going to make a repository, make one yourself if you want to update some files. In this case, I'm calling the Sorugi Linux search screenshots utility. I'm going to make it public. Let's go ahead and add or read me and then choose a license and it has to be MIT because that's what the original was. I think you could probably with MIT, I think it's pretty liberal. You can change it, but let's just keep it. All right. So then I have my repository created. I'm going to copy and paste that. And then from my development station, I'm going to do get clone and then clone in. And then if I can remember my password, nope. Oh, yeah. Okay. Now somebody's going to do analysis on that. So I'm going to have to change my password. All right. So we want to go into search screenshots. And then I just have the license file that was created and the read me file that's created, but everything else is empty. But it is a Git repository. So I've already created that's the directory. I've already pulled out the search screenshot. So I'm going to drop that in there. And that's the original version. I haven't modified it at all. So then if we look in there, we have search screenshots. If I do get status, then we see that a new file was added, but it's not been really at tracked yet. So if I do get add dot, then get status. Now it's green and saying, hey, we see the file. Okay. Now I can do my original commit. So if I do get commit dash M, and then I'll do initial search screenshot. And that is the original commit. So now I have a copy of the original. And if I mess anything up, I can just go back to it. I'm going to do get push to make sure that we push it up. And now it's pushed up to GitHub. Let's go ahead and take a look at our site. And then now we have the search screenshots. If we look at that, that's all of the original code because we haven't modified anything yet. Using Python three software license. This is exactly what we had before inside suruki. So now I can start to edit that code directly. So I'm actually going to go ahead and shut down suruki Linux because I don't usually develop in that environment. So that's more of the investigation side. Free up some resources. So I'm just going to do code. And I use MS code most of the time. And then I just did code dot. And then that's for the current directory. So basically open up the current directory in MS code. We have our license, which should be filled out for MFT. Read me, which hasn't been filled out yet. Let's say something like updated to support subdirectories. That's the read me. You should keep track of the version numbers. Change log. There is a really interesting program. Kind of standard. Let me see if I can find it real quick because it is super useful if you guys are using it for software development. I think it was like changelog standards website. Keep a changelog. I think that was it. Yep. Okay, so what I probably do, I won't do it now just to save some time, but I recommend that anyone who's doing any type of software development goes to keep a changelog.com is super, super useful standard and very easy to use. It's kind of saved me on multiple occasions. So keep a changelog.com highly recommended. Okay, so the first version we had was 2019 1201. So they just do versioning by day. Change log. I just say initial commit. Now our read me is a little bit up to date. I would probably go back and do a little bit more with that, but let's go ahead and get into the code. So we have looks like I'm missing one library CB to. Okay, so the first thing that is an issue is creating this directory. And then we have our art parse. Then we have another directory that's created. And then we just have a bunch, I have a loop with a bunch of if statements inside of it. All right, so what do we want to do? Like how do I want this program to actually work? Okay, so the first thing. Run. Let's say the help menu. So run with help menu. If there's no options or something's wrong. Two, what else do we want to do? The big thing is scan the directory of images for height with. Also scan some directories. Okay, and I also want another feature. Easy to update. Screenshot dimensions. So right now it looks like they have a height and width kind of hard coded into these if statements. Well, I mean, that's really hard to update. We would have to copy this entire block if we wanted to add another size, right? We don't want to do that. So let's go ahead and say easy to update the height and width. And then I think all of these can pretty much be a function because it looks like all of this code is the same. We'll see maybe there's a reason they weren't doing it. Okay, so from the search screenshots, I want to run with a help menu. I want to be able to scan a directory of images for height and width. Either from list or manual input. Scan some directories basically the same from a list or from manual input. And then I wanted to make it easy to update the heights and widths whenever I find new devices and have a new heights and widths. Is that it? Is that all we want to do? I have something that kind of annoyed me. Don't make directories unless actually needed. So like, only make a directory whenever you know you have everything you need to start processing an image. So maybe we find our first image. If we've confirmed that we actually want to process that image, then we create a directory to output to instead of just creating it as soon as it's created. As soon as we run it. Anything else we need to add to that? Okay, so the first thing I'm going to do is propose. What is today? 2021. That switched me over. Sorry about that. So I'm going to propose this change to the spelling error. Let's fix that. Okay. So the first thing. Go into my list again, just to make sure I always make a list like this just to make sure that I kind of stay on track. Otherwise, I'll forget a feature that I'm wanting to implement. With GitHub, normally each of these features would probably be its own branch. Feature branch that I would bounce off of. Since it's all kind of one. I mean, we're essentially refactoring almost the entire script. So I'll just do it all together now. All right, we have our imports. Destination file directory as a global. Go ahead and move all of our global variables together. It looks like this top stuff was probably tacked on afterwards. Destination file directory. I'm going to move that down with the other folder creation. So pretty. So we have our arguments. AP, arg, parse, images, list directory. So the first time that we're actually using. Okay, we get the output directory. And we create it here. Trying to think of how we would refactor this that that actually makes sense. It's kind of, it's easier to just do it without anything there trying to think about how to rearrange it as a bit. Destination file directory. Okay, so what they're doing is creating all the directories creating the destination file. CBS. And then file name right. Basically what probably looks like the titles in the CBS. And then getting the images. So what I would probably do is kind of like setting everything up. That means that we're setting everything up before we know if we need anything. We have our input directory. Open image read. And what this IMG. Okay, that's the image object image file is the data. Using image. Yep. Okay, that's what we're hashing IMG here is the image properties. And then image file is actually the data. So let's go ahead and just mark that way we know image contents, image properties. Okay. Let me print the width of the image. All right. Let's just go ahead and not write this data out. I'm going to go ahead and comment all of this. All right, so I've commented out basically all of the file creation stuff, but I still need images. Okay, so we have our images. We have our input directory. I'm going to remove the file name right. So what this will do is just print everything to the screen and we won't be writing it. Yep. We can definitely turn this into a loop. All right, so I'm going to open up a terminal. See if we can actually run it. A module named. Anyone know the package name for it? CB2. We open CB Python. Let's try that again. Okay. So now it is running and then we actually get an error message. So screenshots and that is the usage following arguments are required, the input directory. So that's actually what we would expect to happen if we give it some information without all the options and it didn't create the directory. So that's perfect. So the next thing to do, I'm thinking about moving all of these into some type of array or list and then reading them out. And maybe I'll make another file like this. And then I'm going to remove all of them except one and then kind of the width image. And that's the one that will keep those into sizes. Okay. And then I would remove that because it's going to be exactly like the other ones. And the goal here is that I'm going to take basically this code block, move it into at least one function, but maybe a couple of different functions. And then just feed the dimension into that function directly. So they do proc kill whenever they're displaying so they are showing the image and then they're basically killing the image later. Once I think the user closes the image, then they kill the process and make sure it's it's killed. I'm not sure if we actually need to show because we are moving all of the images that we find into another directory. So what we could do instead of just showing it as we find it and then blocking. So once they do show, I'm pretty sure that they're blocking all of the other commands. I don't think that they're going to go on and then show a bunch of other images. I'm pretty sure it blocks stops the entire process and then until you click. So what would be better is just have an output directory. Once we extract all of the images, throw them into the output directory and then just show the directory. So let's do six and then say extract to output directory and show directory. So I won't do all of that while you guys are here. I'll just go ahead and start on the loop or the function. Sorry. One of the first functions that we need, I'm going to call, for example, setup, because it looks like we have a bunch of setups to do. So def, setup, I'll just call it setup. Then in there for now we'll just do print, create, output, folders and files. So it looks like there's the output directory and then there's the destination directory. And I think destination directory is probably for the found images themselves and the output directory is for the file that's going to contain all the metadata including the hash values. I'm not sure why they're separating them because we could just have a directory full of likely screenshots and then the metadata inside the same directory. We'll be splitting it out too. I don't think so. I think let's just keep the output directory and then get rid of destination file directory. That'll make things a little bit easier anyway. And output directory is given by the user. So we'll need to check if it's unique. If it's not unique, then we probably need to add a timestamp to it or something like that. Create output folders and files. I'm just going to put a note here. So keep output directory. Only use output directory. Check if exists. Or what are we going to do by default? Or create a random file or create a random file name. Then that's where we could use this kind of date time string that they're using here. That's the destination directory. So if not OS path exists our output directory. So if it doesn't exist, go ahead and make it. And then else would be if it exists. And what we can do is just take that code. But this is going to create it in the same folder that we're running it from. Is that something we want? We can change it. I'm going to say print. At least say what the error is. The output. Please try another name. Something like that. File name. Destination file. I still don't completely understand the difference between the output directory. Excuse me. And the destination file directory. Input directory. Image save. The output directory was where we were saving the images. And then they were just dumping the metadata into the same sub folder. I'm going to create a new variable instead of quoting this all the time. Output directory. Call that out there. And then move all of this out there. Okay. So now we have hit the argument. So we have a setup function. We have the outdoor variable that's being passed in. The outdoor variable is the output directory where we will save both the file metadata CSV file as well as all of the images that we find that we believe are screenshots. We'll check if the output directory path exists. If it doesn't exist, then we'll create it and then inside of that path, we'll create a file with a file name of year month day hour minutes seconds that CSV create that file and then write essentially a header to that file. I might need to actually. Okay, we'll come back to that, but I probably have to put that as a as a variable that we pass as well. Yep, just kind of experimenting around here. And then we probably don't need the destination file directory anymore. And then if not OS path exists, yeah, that's the same one. So I'm going to go ahead and remove that. All right. So so far we've created one function for setup. We're not running it yet. It never gets accessed because we haven't figured out where we want to run it yet. I probably want to run it the first time that I find an image that I want to process. I'm going to take the height and width of all images as they come in on a different line. So that's not great because that's going to give you a lot of text on your screen. Probably don't want that much text. Actually, you should probably do something more like print image. Something like that maybe. And then everything would be on one line and I might even add the file name or something to it later. So I'm going to go ahead and comment these out for now. Just know where I was at. Then we have our first kind of custom width and height. So if we actually do have width, args, arguments of width and height, then we will use them as an example. If not, then we will use all the built in widths and heights. So instead of doing this, if they're just doing a test like this all the time, what we can do to avoid this is just do if, like we're not guaranteed to actually have a width and height argument. And if hard parse has a, it exists. So what we can do is something like if, args. I just want to check if the height and the width was actually given by the user. What they're doing here, actually now that I think about their if statements, first the checking for the custom size. And then if it's not the custom size, they're checking for a different size. So it's not an exclusive I want to look for these sizes. It is in total give me all of these different. So essentially that needs to be checked every single time. Let's go ahead and start the function then check image. And check image will be sent the width and the height right under the def function. Let's go ahead and create another function called def check image. And then with the check sending to arguments or variables to the function check image. And then I can pretty much, I think just copy and paste everything that they have in all of these if statements. But I don't want to image show every single time. That's not going to be right. Image height, image width. And I need to check what are they testing against the actual height and width. Actually, this isn't check image. This is something like process image. I'll call it process image and we need the image data. Because I'll do the checks in a loop underneath that for loop. But again, same line. So we don't have a bunch of lines everywhere. That's the object. And dash values. File name CSB right. Probably going to image and name. I'm sleep. I'm not sure why they're sleeping. Keep that there for a second and then hide the image. We didn't display it. So I'm going to go ahead and comment all of this out for now. Okay. So this actually process image takes the place of a lot of what's going on in this if statement. Get rid of all of that. And then just to process image, we have to give it the image and file name CSB. Okay, so you can already see I basically have a check here. That is just checking the width to the user generated or user given width. And then it just processes the image. And now I can get rid of a lot of these lines of code that's completely redundant over and over again. So I'll work on that later. What else do we get the next thing I wanted to do is actually get all of these into a list. And then basically parse through this list every single time. So maybe load in either the list, load in the list and then do a for loop over it to do all the checking. And then just keep running process image whenever I find anything interesting. Rather than having all of these different if statements, you can do it with a loop and one if statements reading the list. Okay, so that would greatly reduce basically all of this code down to, you know, the loop. Loop over the list plus an if statement and then processing the image or not processing the image. We probably need to keep this if statement with custom width and height just because just because I can't see an easy way to just put it into the list or. Yeah, if it exists, we can just add it to the list and then loop over the entire list and then we can get rid of that as well. So we can pretty much move this down into like three or four lines instead of having this entire thing and it should be a little bit more efficient. It'll also be easier to manage because you can see that I've already created this sizes list and I would probably make it like a CSV file. We have width and height and then maybe even like a comment or something that way we know what's what what this width and height is for. And then what that means is without changing any of the code, I can just come into this particular file, add a new, add a new width and height. And then the next time I run the program, it'll find it. So it's much more maintainable because instead of going in finding the lines editing the code for the different heights and widths, just change one file, anyone who finds a new like common resolution that they're seeing or screenshot size can just come in and edit the file and then we can kind of collaborate a lot easier on this. So I think that'll be a much easier way to maintain everything. Right, so I have a couple problems now that I've named the file name CS and file name CSV inside this function. So the rest of the program can't get access to that file. So what I would have to do instead is create that file name CS variable in another scope outside or I would have to pass it to another function that I'm calling. So for example, specifically this process image I need to pass the file name CSV to that function. So I need to get it somehow. That's one problem I need to solve. I need to call the list, put the users widths and heights into the list. And then basically everything else is just removing this trimming it up and testing that it works. Right. That's unfortunately all I really have time for today. But I hope you guys can see. We took, we took a file that is an interesting program like it's a useful program if you can dump all of the data into a single directory call. That's the other thing I have to do thing is the recursion. But like I said, I think we can recurse at this level here. So images is just an image list. And then OS Lister args input directory all we're using is the OS Lister with the input directory, and then feeding all of those image files into the images list. Now what I think I can do is just add recursion right here. And then that solves our recursion problem so I can just point it to a suspect disk. It will recurse under all the sub directories pull out all of the images that it can find. And then, and then, yeah, we should get the list of images. I'm just thinking now. We don't actually explicitly test for images so they just kind of assume that all of the files that we're reading in our images so we might need to do a test either on the file header or by the extension. So that's something to think about there but that'll come later in the testing, right? So I think I can pretty much get this program down to, you know, less than a quarter of the lines that it used to be. It should be much faster and it should also be easier to maintain and upgrade as we find more screenshot sizes. So that's what I'm going to do right now. I'm going to go ahead and go back into GitHub. So I'm in code now. I have my screenshots. I have my new sizes file. I'm going to go ahead and commit this even though it's not completely ready. So get, add, and then I get status. So I have a couple of different files that I've modified. I'm going to just do get, commit, and then initial start of refactor. Let's do start of refactor because it was quite a bit. Okay. And then get push. And then let's check that it was actually up there, old file, go into screenshots. Let's commit 25 seconds ago. We have our sizes. We have our screenshots pie. I run into there. We should see at least those functions created. Yeah, updated date and then updated functions as well. Right. So you can kind of see what I'm doing. Like I took on a lot with the script actually because I have a lot of functions that I want to implement with it. If you just wanted to add a screenshot size, for example, so in your investigations you found that there's particular screenshot sizes, just adding another if statement to that would have been plenty and it would have been super useful for the community. I'm trying to do a lot here with kind of a total refactor to make it much easier to maintain plus add recursion and all that stuff. So I'm taking on quite a bit, but still not going to take that much longer to actually finish everything up. I just have to create an array, loop over the array, and then run the code that's already been written. So pretty straightforward. Does anyone have any questions about that? And or how to commit or how to contribute to open source projects anyway, or how to get into digital investigations. Now's the time. Okay. Like I said, this is the first time I've ever done a live stream, and especially a coding live stream. So if you liked it, please let me know. I will keep the recording up for a little bit. I'm not sure what I'll do with it for a while, but we'll see. If this was useful for you. Yeah, definitely let me know. If you like to see stuff like this, like I do this kind of thing all the time. If I find a tool that looks interesting, but it just doesn't do exactly what I want, or I'm having some issues with it. I'll usually go in and look at the source code and see if I can just change it real quick. So I do this kind of thing pretty much all the time with tools that I'm using. The next step would be if we get this tool working the way that I want it to, and it's consistent, then I would submit back to the author, Antonio, specifically, send them a copy of this and say, hey, I've updated this. It now does these things. Feel free to use it or not. But I can go ahead and use it. So now for me, this tool would be useful for me if they use it as well. It's good. If one of the things that I'm thinking about showing is how to set up a package repository. So whenever you make your own edits, thanks a lot, Jay. Whenever you make your own edits to software like this, you can create your own package repository. And then upgrade or automatically install them in Sodorugi Linux without having to go through the maintainers of the program. It's basically creating a PPA based on all of our changes. So I might talk about that a little bit later. Yep. Yeah, thank you guys so much and thanks to everyone in the chat and I hope you have a good day. Let me know if you have any questions, comment on the videos. You can also hit me up on Twitter. I'm on there quite a bit at D4 Science. So yeah, thanks a lot.