Created
February 22, 2021 11:40
-
-
Save siilver777/8c7da92bc0661c3ea0135c753d54b760 to your computer and use it in GitHub Desktop.
Command-line Plex folder cleaner, removes SRT files that doesn't match an existing media
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.swift | |
// PlexCleaner | |
// | |
// Created by Jason Pierna on 22/10/2020. | |
// | |
import Foundation | |
struct ValidationError: Error, CustomStringConvertible { | |
private var message: String | |
init(_ message: String) { | |
self.message = message | |
} | |
var description: String { | |
return message | |
} | |
} | |
var path: String! | |
var dryRun: Bool = false | |
func validate() throws { | |
var isDirectory: ObjCBool = false | |
guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) else { | |
throw ValidationError("Provided path does not exist.") | |
} | |
guard isDirectory.boolValue else { | |
throw ValidationError("Provided path is not a directory.") | |
} | |
} | |
func run() throws { | |
getFolders(at: path).forEach(cleanFolder) | |
} | |
private func contentOfFolder(at path: String) -> [String] { | |
let contentsOfFolder = try? FileManager.default.contentsOfDirectory(atPath: path) | |
.filter { $0 != ".DS_Store" } | |
.map { "\(path)/\($0)" } | |
return contentsOfFolder ?? [] | |
} | |
private func getFolders(at path: String) -> [String] { | |
let contentsOfFolder = contentOfFolder(at: path) | |
return contentsOfFolder.filter { | |
var isDirectory: ObjCBool = false | |
_ = FileManager.default.fileExists(atPath: $0, isDirectory: &isDirectory) | |
return isDirectory.boolValue | |
} | |
} | |
private func cleanFolder(folder: String) { | |
let videoType = "mp4" | |
let nestedFolders = getFolders(at: folder) | |
let videoFiles = getFilesOfType(videoType, in: folder) | |
let srtFiles = getFilesOfType("srt", in: folder) | |
getUnmatchedSRTFiles(srt: srtFiles, videos: videoFiles, ofType: videoType).forEach(trashFile) | |
nestedFolders.forEach(cleanFolder) | |
let contentsOfFolder = contentOfFolder(at: folder) | |
if contentsOfFolder.count == 0 { | |
trashFile(filePath: folder) | |
} | |
} | |
private func getFilesOfType(_ type: String, in folder: String) -> [String] { | |
let contentsOfFolder = contentOfFolder(at: folder) | |
return contentsOfFolder.filter { $0.hasSuffix(".\(type)") } | |
} | |
private func getUnmatchedSRTFiles(srt: [String], videos: [String], ofType type: String) -> [String] { | |
return srt.filter { srtFile in | |
return !videos.contains(where: { videoFile in | |
let videoFilenameWithoutExt = videoFile.replacingOccurrences(of: ".\(type)", with: "") | |
return srtFile.hasPrefix(videoFilenameWithoutExt) | |
}) | |
} | |
} | |
private func trashFile(filePath: String) { | |
let url = URL(fileURLWithPath: filePath) | |
do { | |
if dryRun { | |
print("TRASH:", filePath) | |
} else { | |
try FileManager.default.trashItem(at: url, resultingItemURL: nil) | |
} | |
} catch { | |
print("Error while trashing \(filePath)", error, error.localizedDescription) | |
} | |
} | |
private func displayUsage() { | |
} | |
do { | |
let args = CommandLine.arguments | |
guard args.count > 1 else { | |
throw ValidationError("Missing parameter: <path>") | |
} | |
path = args[1] | |
guard args.count <= 3 else { | |
throw ValidationError("Too much parameters!") | |
} | |
if args.count == 3 { | |
if args[2] == "--dry-run" { | |
dryRun = true | |
} else { | |
throw ValidationError("Wrong flag. Use --dry-run.") | |
} | |
} | |
try run() | |
} catch { | |
print("Error:", error.localizedDescription) | |
displayUsage() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment