├── .gitignore ├── LICENSE ├── README.md ├── SaveHollywood.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── SaveHollywood ├── NSArray+Shuffle.h ├── NSArray+Shuffle.m ├── NSColor+String.h ├── NSColor+String.m ├── NSIndexSet+Analysis.h ├── NSIndexSet+Analysis.m ├── SHAboutBoxWindowController.h ├── SHAboutBoxWindowController.m ├── SHAboutBoxWindowController.xib ├── SHAssetTableCellView.h ├── SHAssetTableCellView.m ├── SHConfigurationWindowController.h ├── SHConfigurationWindowController.m ├── SHLightGrayBackgroundView.h ├── SHLightGrayBackgroundView.m ├── SHPlayingAssetsRegister.h ├── SHPlayingAssetsRegister.m ├── SHSecondaryBox.h ├── SHSecondaryBox.m ├── SHSettings.h ├── SHSettings.m ├── SHSlider.h ├── SHSlider.m ├── SHTokenView.h ├── SHTokenView.m ├── SHUserDefaults+Constants.h ├── SHUserDefaults+Constants.m ├── SHView.h ├── SHView.m ├── SaveHollywood-Info.plist ├── SaveHollywood-Prefix.pch ├── SaveHollywoodView.h ├── SaveHollywoodView.m ├── en.lproj ├── Localized.strings └── SHConfigurationWindowController.xib ├── fr.lproj ├── Localized.strings └── SHConfigurationWindowController.xib ├── thumbnail.png └── thumbnail@2x.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/packagesdev/savehollywood/435570bd65e70f4a7b3b8c570b989174b62b8755/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | savehollywood 2 | ============= 3 | 4 | SaveHollywood Screen Saver 5 | -------------------------------------------------------------------------------- /SaveHollywood.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F4015D19169CB3C000560296 /* SHConfigurationWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4015D16169CB3C000560296 /* SHConfigurationWindowController.h */; }; 11 | F4015D1A169CB3C000560296 /* SHConfigurationWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = F4015D17169CB3C000560296 /* SHConfigurationWindowController.m */; }; 12 | F4015D1F169CB47D00560296 /* SHUserDefaults+Constants.h in Headers */ = {isa = PBXBuildFile; fileRef = F4015D1D169CB47D00560296 /* SHUserDefaults+Constants.h */; }; 13 | F4015D20169CB47D00560296 /* SHUserDefaults+Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = F4015D1E169CB47D00560296 /* SHUserDefaults+Constants.m */; }; 14 | F40427DF169B76CB00B146F7 /* SaveHollywoodView.m in Sources */ = {isa = PBXBuildFile; fileRef = F40427DE169B76CB00B146F7 /* SaveHollywoodView.m */; }; 15 | F405C93016DC01D700EFDF39 /* SHTokenView.h in Headers */ = {isa = PBXBuildFile; fileRef = F405C92E16DC01D700EFDF39 /* SHTokenView.h */; }; 16 | F405C93116DC01D700EFDF39 /* SHTokenView.m in Sources */ = {isa = PBXBuildFile; fileRef = F405C92F16DC01D700EFDF39 /* SHTokenView.m */; }; 17 | F4066EA7170760EA00EBE7D0 /* thumbnail.png in Resources */ = {isa = PBXBuildFile; fileRef = F4066EA5170760EA00EBE7D0 /* thumbnail.png */; }; 18 | F4066EA8170760EA00EBE7D0 /* thumbnail@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F4066EA6170760EA00EBE7D0 /* thumbnail@2x.png */; }; 19 | F40B998B16AB1F6200644F61 /* NSColor+String.h in Headers */ = {isa = PBXBuildFile; fileRef = F40B998916AB1F6200644F61 /* NSColor+String.h */; }; 20 | F40B998C16AB1F6200644F61 /* NSColor+String.m in Sources */ = {isa = PBXBuildFile; fileRef = F40B998A16AB1F6200644F61 /* NSColor+String.m */; }; 21 | F434961B16B701B500C549DF /* Localized.strings in Resources */ = {isa = PBXBuildFile; fileRef = F434961916B701B500C549DF /* Localized.strings */; }; 22 | F44979572B53010100A1558A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F44979562B53010100A1558A /* Cocoa.framework */; }; 23 | F44979592B53010B00A1558A /* ScreenSaver.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F44979582B53010B00A1558A /* ScreenSaver.framework */; }; 24 | F449795B2B53011B00A1558A /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F449795A2B53011B00A1558A /* AVFoundation.framework */; }; 25 | F449795D2B53017B00A1558A /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F449795C2B53017B00A1558A /* CoreMedia.framework */; }; 26 | F449795F2B5301B200A1558A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F449795E2B5301B200A1558A /* QuartzCore.framework */; }; 27 | F45A65182117329400E5A4D4 /* SHPlayingAssetsRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = F45A65162117329400E5A4D4 /* SHPlayingAssetsRegister.h */; }; 28 | F45A65192117329400E5A4D4 /* SHPlayingAssetsRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = F45A65172117329400E5A4D4 /* SHPlayingAssetsRegister.m */; }; 29 | F4875FC5211A50F1007D8759 /* SHView.h in Headers */ = {isa = PBXBuildFile; fileRef = F4875FC3211A50F1007D8759 /* SHView.h */; }; 30 | F4875FC6211A50F1007D8759 /* SHView.m in Sources */ = {isa = PBXBuildFile; fileRef = F4875FC4211A50F1007D8759 /* SHView.m */; }; 31 | F4AB34BE16BED1CF00015DB9 /* SHAssetTableCellView.h in Headers */ = {isa = PBXBuildFile; fileRef = F4AB34BC16BED1CF00015DB9 /* SHAssetTableCellView.h */; }; 32 | F4AB34BF16BED1CF00015DB9 /* SHAssetTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = F4AB34BD16BED1CF00015DB9 /* SHAssetTableCellView.m */; }; 33 | F4B3933316ED43C40061B52E /* SHSlider.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B3933116ED43C40061B52E /* SHSlider.h */; }; 34 | F4B3933416ED43C40061B52E /* SHSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = F4B3933216ED43C40061B52E /* SHSlider.m */; }; 35 | F4B4F906218510FF00C23130 /* SHSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B4F904218510FF00C23130 /* SHSettings.h */; }; 36 | F4B4F907218510FF00C23130 /* SHSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F4B4F905218510FF00C23130 /* SHSettings.m */; }; 37 | F4B9BCEE16D54A8B00051854 /* NSIndexSet+Analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = F4B9BCEC16D54A8B00051854 /* NSIndexSet+Analysis.h */; }; 38 | F4B9BCEF16D54A8B00051854 /* NSIndexSet+Analysis.m in Sources */ = {isa = PBXBuildFile; fileRef = F4B9BCED16D54A8B00051854 /* NSIndexSet+Analysis.m */; }; 39 | F4BB43A516BD387100443067 /* SHSecondaryBox.h in Headers */ = {isa = PBXBuildFile; fileRef = F4BB43A316BD387100443067 /* SHSecondaryBox.h */; }; 40 | F4BB43A616BD387100443067 /* SHSecondaryBox.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BB43A416BD387100443067 /* SHSecondaryBox.m */; }; 41 | F4BB43B116BD3A9B00443067 /* SHLightGrayBackgroundView.h in Headers */ = {isa = PBXBuildFile; fileRef = F4BB43AF16BD3A9B00443067 /* SHLightGrayBackgroundView.h */; }; 42 | F4BB43B216BD3A9B00443067 /* SHLightGrayBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BB43B016BD3A9B00443067 /* SHLightGrayBackgroundView.m */; }; 43 | F4BC1E3816B4936200A580F9 /* NSArray+Shuffle.h in Headers */ = {isa = PBXBuildFile; fileRef = F4BC1E3616B4936200A580F9 /* NSArray+Shuffle.h */; }; 44 | F4BC1E3916B4936200A580F9 /* NSArray+Shuffle.m in Sources */ = {isa = PBXBuildFile; fileRef = F4BC1E3716B4936200A580F9 /* NSArray+Shuffle.m */; }; 45 | F4DD2AA016FDBF30002A555F /* SHConfigurationWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4DD2A9D16FDBF30002A555F /* SHConfigurationWindowController.xib */; }; 46 | F4DD2AA316FDBF48002A555F /* SHConfigurationWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4DD2A9D16FDBF30002A555F /* SHConfigurationWindowController.xib */; }; 47 | F4DD2AA516FDBF73002A555F /* SHAboutBoxWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4DD2AA416FDBF73002A555F /* SHAboutBoxWindowController.xib */; }; 48 | F4EF51BC16FA281500D1A5C6 /* SHAboutBoxWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4EF51B916FA281500D1A5C6 /* SHAboutBoxWindowController.h */; }; 49 | F4EF51BD16FA281500D1A5C6 /* SHAboutBoxWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EF51BA16FA281500D1A5C6 /* SHAboutBoxWindowController.m */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | F4015D16169CB3C000560296 /* SHConfigurationWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHConfigurationWindowController.h; sourceTree = ""; }; 54 | F4015D17169CB3C000560296 /* SHConfigurationWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHConfigurationWindowController.m; sourceTree = ""; }; 55 | F4015D1D169CB47D00560296 /* SHUserDefaults+Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SHUserDefaults+Constants.h"; sourceTree = ""; }; 56 | F4015D1E169CB47D00560296 /* SHUserDefaults+Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SHUserDefaults+Constants.m"; sourceTree = ""; }; 57 | F40427CB169B76CB00B146F7 /* SaveHollywood.saver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SaveHollywood.saver; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | F40427D8169B76CB00B146F7 /* SaveHollywood-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SaveHollywood-Info.plist"; sourceTree = ""; }; 59 | F40427DC169B76CB00B146F7 /* SaveHollywood-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SaveHollywood-Prefix.pch"; sourceTree = ""; }; 60 | F40427DD169B76CB00B146F7 /* SaveHollywoodView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SaveHollywoodView.h; sourceTree = ""; }; 61 | F40427DE169B76CB00B146F7 /* SaveHollywoodView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SaveHollywoodView.m; sourceTree = ""; }; 62 | F405C92E16DC01D700EFDF39 /* SHTokenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHTokenView.h; sourceTree = ""; }; 63 | F405C92F16DC01D700EFDF39 /* SHTokenView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHTokenView.m; sourceTree = ""; }; 64 | F4066EA5170760EA00EBE7D0 /* thumbnail.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumbnail.png; sourceTree = ""; }; 65 | F4066EA6170760EA00EBE7D0 /* thumbnail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumbnail@2x.png"; sourceTree = ""; }; 66 | F40B998916AB1F6200644F61 /* NSColor+String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSColor+String.h"; sourceTree = ""; }; 67 | F40B998A16AB1F6200644F61 /* NSColor+String.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSColor+String.m"; sourceTree = ""; }; 68 | F4121CCC16FD06200059A794 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localized.strings; sourceTree = ""; }; 69 | F434961A16B701B500C549DF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localized.strings; sourceTree = ""; }; 70 | F44979562B53010100A1558A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; 71 | F44979582B53010B00A1558A /* ScreenSaver.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScreenSaver.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/ScreenSaver.framework; sourceTree = DEVELOPER_DIR; }; 72 | F449795A2B53011B00A1558A /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; 73 | F449795C2B53017B00A1558A /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/CoreMedia.framework; sourceTree = DEVELOPER_DIR; }; 74 | F449795E2B5301B200A1558A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; 75 | F45A65162117329400E5A4D4 /* SHPlayingAssetsRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHPlayingAssetsRegister.h; sourceTree = ""; }; 76 | F45A65172117329400E5A4D4 /* SHPlayingAssetsRegister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHPlayingAssetsRegister.m; sourceTree = ""; }; 77 | F4875FC3211A50F1007D8759 /* SHView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHView.h; sourceTree = ""; }; 78 | F4875FC4211A50F1007D8759 /* SHView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHView.m; sourceTree = ""; }; 79 | F4AB34BC16BED1CF00015DB9 /* SHAssetTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHAssetTableCellView.h; sourceTree = ""; }; 80 | F4AB34BD16BED1CF00015DB9 /* SHAssetTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHAssetTableCellView.m; sourceTree = ""; }; 81 | F4B3933116ED43C40061B52E /* SHSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHSlider.h; sourceTree = ""; }; 82 | F4B3933216ED43C40061B52E /* SHSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHSlider.m; sourceTree = ""; }; 83 | F4B4F904218510FF00C23130 /* SHSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHSettings.h; sourceTree = ""; }; 84 | F4B4F905218510FF00C23130 /* SHSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHSettings.m; sourceTree = ""; }; 85 | F4B9BCEC16D54A8B00051854 /* NSIndexSet+Analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+Analysis.h"; sourceTree = ""; }; 86 | F4B9BCED16D54A8B00051854 /* NSIndexSet+Analysis.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexSet+Analysis.m"; sourceTree = ""; }; 87 | F4BB43A316BD387100443067 /* SHSecondaryBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHSecondaryBox.h; sourceTree = ""; }; 88 | F4BB43A416BD387100443067 /* SHSecondaryBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHSecondaryBox.m; sourceTree = ""; }; 89 | F4BB43AF16BD3A9B00443067 /* SHLightGrayBackgroundView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHLightGrayBackgroundView.h; sourceTree = ""; }; 90 | F4BB43B016BD3A9B00443067 /* SHLightGrayBackgroundView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHLightGrayBackgroundView.m; sourceTree = ""; }; 91 | F4BC1E3616B4936200A580F9 /* NSArray+Shuffle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Shuffle.h"; sourceTree = ""; }; 92 | F4BC1E3716B4936200A580F9 /* NSArray+Shuffle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Shuffle.m"; sourceTree = ""; }; 93 | F4DD2A9E16FDBF30002A555F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/SHConfigurationWindowController.xib; sourceTree = ""; }; 94 | F4DD2AA216FDBF48002A555F /* fr */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = fr; path = fr.lproj/SHConfigurationWindowController.xib; sourceTree = ""; }; 95 | F4DD2AA416FDBF73002A555F /* SHAboutBoxWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SHAboutBoxWindowController.xib; sourceTree = ""; }; 96 | F4EF51B916FA281500D1A5C6 /* SHAboutBoxWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHAboutBoxWindowController.h; sourceTree = ""; }; 97 | F4EF51BA16FA281500D1A5C6 /* SHAboutBoxWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHAboutBoxWindowController.m; sourceTree = ""; }; 98 | /* End PBXFileReference section */ 99 | 100 | /* Begin PBXFrameworksBuildPhase section */ 101 | F40427C6169B76CB00B146F7 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | F449795F2B5301B200A1558A /* QuartzCore.framework in Frameworks */, 106 | F449795D2B53017B00A1558A /* CoreMedia.framework in Frameworks */, 107 | F449795B2B53011B00A1558A /* AVFoundation.framework in Frameworks */, 108 | F44979592B53010B00A1558A /* ScreenSaver.framework in Frameworks */, 109 | F44979572B53010100A1558A /* Cocoa.framework in Frameworks */, 110 | ); 111 | runOnlyForDeploymentPostprocessing = 0; 112 | }; 113 | /* End PBXFrameworksBuildPhase section */ 114 | 115 | /* Begin PBXGroup section */ 116 | F40427BE169B76CB00B146F7 = { 117 | isa = PBXGroup; 118 | children = ( 119 | F40427D6169B76CB00B146F7 /* SaveHollywood */, 120 | F40427CD169B76CB00B146F7 /* Frameworks */, 121 | F40427CC169B76CB00B146F7 /* Products */, 122 | ); 123 | sourceTree = ""; 124 | }; 125 | F40427CC169B76CB00B146F7 /* Products */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | F40427CB169B76CB00B146F7 /* SaveHollywood.saver */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | F40427CD169B76CB00B146F7 /* Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | F449795E2B5301B200A1558A /* QuartzCore.framework */, 137 | F449795C2B53017B00A1558A /* CoreMedia.framework */, 138 | F449795A2B53011B00A1558A /* AVFoundation.framework */, 139 | F44979582B53010B00A1558A /* ScreenSaver.framework */, 140 | F44979562B53010100A1558A /* Cocoa.framework */, 141 | ); 142 | name = Frameworks; 143 | sourceTree = ""; 144 | }; 145 | F40427D6169B76CB00B146F7 /* SaveHollywood */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | F40B998916AB1F6200644F61 /* NSColor+String.h */, 149 | F40B998A16AB1F6200644F61 /* NSColor+String.m */, 150 | F4B9BCEC16D54A8B00051854 /* NSIndexSet+Analysis.h */, 151 | F4B9BCED16D54A8B00051854 /* NSIndexSet+Analysis.m */, 152 | F4BC1E3616B4936200A580F9 /* NSArray+Shuffle.h */, 153 | F4BC1E3716B4936200A580F9 /* NSArray+Shuffle.m */, 154 | F4015D1D169CB47D00560296 /* SHUserDefaults+Constants.h */, 155 | F4015D1E169CB47D00560296 /* SHUserDefaults+Constants.m */, 156 | F45A65162117329400E5A4D4 /* SHPlayingAssetsRegister.h */, 157 | F45A65172117329400E5A4D4 /* SHPlayingAssetsRegister.m */, 158 | F40427DD169B76CB00B146F7 /* SaveHollywoodView.h */, 159 | F40427DE169B76CB00B146F7 /* SaveHollywoodView.m */, 160 | F4B4F904218510FF00C23130 /* SHSettings.h */, 161 | F4B4F905218510FF00C23130 /* SHSettings.m */, 162 | F40BA60F16BEC6C000154844 /* Configuration */, 163 | F40427D7169B76CB00B146F7 /* Supporting Files */, 164 | ); 165 | path = SaveHollywood; 166 | sourceTree = ""; 167 | }; 168 | F40427D7169B76CB00B146F7 /* Supporting Files */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | F40427D8169B76CB00B146F7 /* SaveHollywood-Info.plist */, 172 | F4066EA5170760EA00EBE7D0 /* thumbnail.png */, 173 | F4066EA6170760EA00EBE7D0 /* thumbnail@2x.png */, 174 | F434961916B701B500C549DF /* Localized.strings */, 175 | F40427DC169B76CB00B146F7 /* SaveHollywood-Prefix.pch */, 176 | ); 177 | name = "Supporting Files"; 178 | sourceTree = ""; 179 | }; 180 | F40BA60F16BEC6C000154844 /* Configuration */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | F40BA61116BEC6D700154844 /* Custom Views */, 184 | F4015D16169CB3C000560296 /* SHConfigurationWindowController.h */, 185 | F4015D17169CB3C000560296 /* SHConfigurationWindowController.m */, 186 | F4DD2A9D16FDBF30002A555F /* SHConfigurationWindowController.xib */, 187 | F4EF51B916FA281500D1A5C6 /* SHAboutBoxWindowController.h */, 188 | F4EF51BA16FA281500D1A5C6 /* SHAboutBoxWindowController.m */, 189 | F4DD2AA416FDBF73002A555F /* SHAboutBoxWindowController.xib */, 190 | ); 191 | name = Configuration; 192 | sourceTree = ""; 193 | }; 194 | F40BA61116BEC6D700154844 /* Custom Views */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | F4875FC3211A50F1007D8759 /* SHView.h */, 198 | F4875FC4211A50F1007D8759 /* SHView.m */, 199 | F4BB43A316BD387100443067 /* SHSecondaryBox.h */, 200 | F4BB43A416BD387100443067 /* SHSecondaryBox.m */, 201 | F4BB43AF16BD3A9B00443067 /* SHLightGrayBackgroundView.h */, 202 | F4BB43B016BD3A9B00443067 /* SHLightGrayBackgroundView.m */, 203 | F4AB34BC16BED1CF00015DB9 /* SHAssetTableCellView.h */, 204 | F4AB34BD16BED1CF00015DB9 /* SHAssetTableCellView.m */, 205 | F405C92E16DC01D700EFDF39 /* SHTokenView.h */, 206 | F405C92F16DC01D700EFDF39 /* SHTokenView.m */, 207 | F4B3933116ED43C40061B52E /* SHSlider.h */, 208 | F4B3933216ED43C40061B52E /* SHSlider.m */, 209 | ); 210 | name = "Custom Views"; 211 | sourceTree = ""; 212 | }; 213 | /* End PBXGroup section */ 214 | 215 | /* Begin PBXHeadersBuildPhase section */ 216 | F40427C7169B76CB00B146F7 /* Headers */ = { 217 | isa = PBXHeadersBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | F4015D19169CB3C000560296 /* SHConfigurationWindowController.h in Headers */, 221 | F4015D1F169CB47D00560296 /* SHUserDefaults+Constants.h in Headers */, 222 | F40B998B16AB1F6200644F61 /* NSColor+String.h in Headers */, 223 | F4BC1E3816B4936200A580F9 /* NSArray+Shuffle.h in Headers */, 224 | F4B4F906218510FF00C23130 /* SHSettings.h in Headers */, 225 | F4BB43A516BD387100443067 /* SHSecondaryBox.h in Headers */, 226 | F4BB43B116BD3A9B00443067 /* SHLightGrayBackgroundView.h in Headers */, 227 | F4AB34BE16BED1CF00015DB9 /* SHAssetTableCellView.h in Headers */, 228 | F4B9BCEE16D54A8B00051854 /* NSIndexSet+Analysis.h in Headers */, 229 | F405C93016DC01D700EFDF39 /* SHTokenView.h in Headers */, 230 | F4B3933316ED43C40061B52E /* SHSlider.h in Headers */, 231 | F4875FC5211A50F1007D8759 /* SHView.h in Headers */, 232 | F45A65182117329400E5A4D4 /* SHPlayingAssetsRegister.h in Headers */, 233 | F4EF51BC16FA281500D1A5C6 /* SHAboutBoxWindowController.h in Headers */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXHeadersBuildPhase section */ 238 | 239 | /* Begin PBXNativeTarget section */ 240 | F40427CA169B76CB00B146F7 /* SaveHollywood */ = { 241 | isa = PBXNativeTarget; 242 | buildConfigurationList = F40427E2169B76CB00B146F7 /* Build configuration list for PBXNativeTarget "SaveHollywood" */; 243 | buildPhases = ( 244 | F40427C5169B76CB00B146F7 /* Sources */, 245 | F40427C6169B76CB00B146F7 /* Frameworks */, 246 | F40427C7169B76CB00B146F7 /* Headers */, 247 | F40427C8169B76CB00B146F7 /* Resources */, 248 | F40427C9169B76CB00B146F7 /* Rez */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = SaveHollywood; 255 | productName = SaveHollywood; 256 | productReference = F40427CB169B76CB00B146F7 /* SaveHollywood.saver */; 257 | productType = "com.apple.product-type.bundle"; 258 | }; 259 | /* End PBXNativeTarget section */ 260 | 261 | /* Begin PBXProject section */ 262 | F40427C0169B76CB00B146F7 /* Project object */ = { 263 | isa = PBXProject; 264 | attributes = { 265 | CLASSPREFIX = SH; 266 | LastUpgradeCheck = 0440; 267 | ORGANIZATIONNAME = WhiteBox; 268 | }; 269 | buildConfigurationList = F40427C3169B76CB00B146F7 /* Build configuration list for PBXProject "SaveHollywood" */; 270 | compatibilityVersion = "Xcode 3.2"; 271 | developmentRegion = English; 272 | hasScannedForEncodings = 0; 273 | knownRegions = ( 274 | en, 275 | fr, 276 | ); 277 | mainGroup = F40427BE169B76CB00B146F7; 278 | productRefGroup = F40427CC169B76CB00B146F7 /* Products */; 279 | projectDirPath = ""; 280 | projectRoot = ""; 281 | targets = ( 282 | F40427CA169B76CB00B146F7 /* SaveHollywood */, 283 | ); 284 | }; 285 | /* End PBXProject section */ 286 | 287 | /* Begin PBXResourcesBuildPhase section */ 288 | F40427C8169B76CB00B146F7 /* Resources */ = { 289 | isa = PBXResourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | F434961B16B701B500C549DF /* Localized.strings in Resources */, 293 | F4DD2AA016FDBF30002A555F /* SHConfigurationWindowController.xib in Resources */, 294 | F4DD2AA316FDBF48002A555F /* SHConfigurationWindowController.xib in Resources */, 295 | F4DD2AA516FDBF73002A555F /* SHAboutBoxWindowController.xib in Resources */, 296 | F4066EA7170760EA00EBE7D0 /* thumbnail.png in Resources */, 297 | F4066EA8170760EA00EBE7D0 /* thumbnail@2x.png in Resources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXResourcesBuildPhase section */ 302 | 303 | /* Begin PBXRezBuildPhase section */ 304 | F40427C9169B76CB00B146F7 /* Rez */ = { 305 | isa = PBXRezBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | /* End PBXRezBuildPhase section */ 312 | 313 | /* Begin PBXSourcesBuildPhase section */ 314 | F40427C5169B76CB00B146F7 /* Sources */ = { 315 | isa = PBXSourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | F40427DF169B76CB00B146F7 /* SaveHollywoodView.m in Sources */, 319 | F4015D20169CB47D00560296 /* SHUserDefaults+Constants.m in Sources */, 320 | F45A65192117329400E5A4D4 /* SHPlayingAssetsRegister.m in Sources */, 321 | F4875FC6211A50F1007D8759 /* SHView.m in Sources */, 322 | F4015D1A169CB3C000560296 /* SHConfigurationWindowController.m in Sources */, 323 | F40B998C16AB1F6200644F61 /* NSColor+String.m in Sources */, 324 | F4BC1E3916B4936200A580F9 /* NSArray+Shuffle.m in Sources */, 325 | F4BB43A616BD387100443067 /* SHSecondaryBox.m in Sources */, 326 | F4B4F907218510FF00C23130 /* SHSettings.m in Sources */, 327 | F4BB43B216BD3A9B00443067 /* SHLightGrayBackgroundView.m in Sources */, 328 | F4AB34BF16BED1CF00015DB9 /* SHAssetTableCellView.m in Sources */, 329 | F4B9BCEF16D54A8B00051854 /* NSIndexSet+Analysis.m in Sources */, 330 | F405C93116DC01D700EFDF39 /* SHTokenView.m in Sources */, 331 | F4B3933416ED43C40061B52E /* SHSlider.m in Sources */, 332 | F4EF51BD16FA281500D1A5C6 /* SHAboutBoxWindowController.m in Sources */, 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | /* End PBXSourcesBuildPhase section */ 337 | 338 | /* Begin PBXVariantGroup section */ 339 | F434961916B701B500C549DF /* Localized.strings */ = { 340 | isa = PBXVariantGroup; 341 | children = ( 342 | F434961A16B701B500C549DF /* en */, 343 | F4121CCC16FD06200059A794 /* fr */, 344 | ); 345 | name = Localized.strings; 346 | sourceTree = ""; 347 | }; 348 | F4DD2A9D16FDBF30002A555F /* SHConfigurationWindowController.xib */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | F4DD2A9E16FDBF30002A555F /* en */, 352 | F4DD2AA216FDBF48002A555F /* fr */, 353 | ); 354 | name = SHConfigurationWindowController.xib; 355 | sourceTree = ""; 356 | }; 357 | /* End PBXVariantGroup section */ 358 | 359 | /* Begin XCBuildConfiguration section */ 360 | F40427E0169B76CB00B146F7 /* Debug */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | ALWAYS_SEARCH_USER_PATHS = NO; 364 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 366 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 367 | CODE_SIGN_IDENTITY = ""; 368 | COPY_PHASE_STRIP = NO; 369 | GCC_C_LANGUAGE_STANDARD = gnu99; 370 | GCC_DYNAMIC_NO_PIC = NO; 371 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 372 | GCC_OPTIMIZATION_LEVEL = 0; 373 | GCC_PREPROCESSOR_DEFINITIONS = ( 374 | "DEBUG=1", 375 | "$(inherited)", 376 | ); 377 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 378 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 379 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 380 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 381 | GCC_WARN_UNUSED_VARIABLE = YES; 382 | MACOSX_DEPLOYMENT_TARGET = 10.9; 383 | ONLY_ACTIVE_ARCH = YES; 384 | SDKROOT = macosx10.9; 385 | }; 386 | name = Debug; 387 | }; 388 | F40427E1169B76CB00B146F7 /* Release */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | ALWAYS_SEARCH_USER_PATHS = NO; 392 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 394 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 395 | CODE_SIGN_IDENTITY = ""; 396 | COPY_PHASE_STRIP = YES; 397 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 398 | GCC_C_LANGUAGE_STANDARD = gnu99; 399 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 400 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 401 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 402 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 403 | GCC_WARN_UNUSED_VARIABLE = YES; 404 | MACOSX_DEPLOYMENT_TARGET = 10.9; 405 | SDKROOT = macosx10.9; 406 | }; 407 | name = Release; 408 | }; 409 | F40427E3169B76CB00B146F7 /* Debug */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | COMBINE_HIDPI_IMAGES = YES; 413 | CURRENT_PROJECT_VERSION = 10; 414 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 415 | GCC_PREFIX_HEADER = "SaveHollywood/SaveHollywood-Prefix.pch"; 416 | INFOPLIST_FILE = "SaveHollywood/SaveHollywood-Info.plist"; 417 | INSTALL_PATH = "$(HOME)/Library/Screen Savers"; 418 | PRODUCT_NAME = "$(TARGET_NAME)"; 419 | SDKROOT = macosx; 420 | VERSIONING_SYSTEM = "apple-generic"; 421 | WRAPPER_EXTENSION = saver; 422 | }; 423 | name = Debug; 424 | }; 425 | F40427E4169B76CB00B146F7 /* Release */ = { 426 | isa = XCBuildConfiguration; 427 | buildSettings = { 428 | COMBINE_HIDPI_IMAGES = YES; 429 | CURRENT_PROJECT_VERSION = 10; 430 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 431 | GCC_PREFIX_HEADER = "SaveHollywood/SaveHollywood-Prefix.pch"; 432 | INFOPLIST_FILE = "SaveHollywood/SaveHollywood-Info.plist"; 433 | INSTALL_PATH = "$(HOME)/Library/Screen Savers"; 434 | PRODUCT_NAME = "$(TARGET_NAME)"; 435 | SDKROOT = macosx; 436 | VERSIONING_SYSTEM = "apple-generic"; 437 | WRAPPER_EXTENSION = saver; 438 | }; 439 | name = Release; 440 | }; 441 | /* End XCBuildConfiguration section */ 442 | 443 | /* Begin XCConfigurationList section */ 444 | F40427C3169B76CB00B146F7 /* Build configuration list for PBXProject "SaveHollywood" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | F40427E0169B76CB00B146F7 /* Debug */, 448 | F40427E1169B76CB00B146F7 /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | defaultConfigurationName = Release; 452 | }; 453 | F40427E2169B76CB00B146F7 /* Build configuration list for PBXNativeTarget "SaveHollywood" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | F40427E3169B76CB00B146F7 /* Debug */, 457 | F40427E4169B76CB00B146F7 /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | /* End XCConfigurationList section */ 463 | }; 464 | rootObject = F40427C0169B76CB00B146F7 /* Project object */; 465 | } 466 | -------------------------------------------------------------------------------- /SaveHollywood.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SaveHollywood.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SaveHollywood/NSArray+Shuffle.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSArray (Shuffle) 4 | 5 | - (NSArray *)shuffledArray; 6 | 7 | @end 8 | 9 | @interface NSMutableArray (Shuffle) 10 | 11 | - (void)shuffle; 12 | 13 | @end -------------------------------------------------------------------------------- /SaveHollywood/NSArray+Shuffle.m: -------------------------------------------------------------------------------- 1 | #import "NSArray+Shuffle.h" 2 | 3 | #include 4 | 5 | @implementation NSArray (Shuffle) 6 | 7 | - (NSArray *)shuffledArray 8 | { 9 | NSMutableArray * tMutableArray=[[self mutableCopy] autorelease]; 10 | 11 | [tMutableArray shuffle]; 12 | 13 | return tMutableArray; 14 | } 15 | 16 | @end 17 | 18 | @implementation NSMutableArray (Shuffle) 19 | 20 | - (void)shuffle 21 | { 22 | NSUInteger tIndex,tCount=[self count]; 23 | 24 | for(tIndex=0;tIndex 2 | 3 | @interface NSColor (String) 4 | 5 | + (NSColor *)colorFromString:(NSString *)inString; 6 | 7 | - (NSString *)stringValue; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /SaveHollywood/NSColor+String.m: -------------------------------------------------------------------------------- 1 | #import "NSColor+String.h" 2 | 3 | @implementation NSColor (String) 4 | 5 | + (NSColor *)colorFromString:(NSString *)inString 6 | { 7 | NSColor * tColor=nil; 8 | 9 | if (inString!=nil) 10 | { 11 | NSArray * tComponents=[inString componentsSeparatedByString:@"|"]; 12 | 13 | if ([tComponents count]==3) 14 | { 15 | tColor=[NSColor colorWithCalibratedRed:[tComponents[0] floatValue] 16 | green:[tComponents[1] floatValue] 17 | blue:[tComponents[2] floatValue] 18 | alpha:1.0]; 19 | } 20 | } 21 | 22 | return tColor; 23 | } 24 | 25 | #pragma mark - 26 | 27 | - (NSString *)stringValue 28 | { 29 | NSColor *tColor = [self colorUsingColorSpaceName:@"NSCalibratedRGBColorSpace"]; 30 | 31 | return([NSString stringWithFormat:@"%f|%f|%f",(float)[tColor redComponent],(float)[tColor greenComponent],(float)[tColor blueComponent]]); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /SaveHollywood/NSIndexSet+Analysis.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | @interface NSIndexSet (Analysis) 17 | 18 | - (BOOL)containsOnlyOneRange; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /SaveHollywood/NSIndexSet+Analysis.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "NSIndexSet+Analysis.h" 15 | 16 | @implementation NSIndexSet (Analaysis) 17 | 18 | - (BOOL)containsOnlyOneRange 19 | { 20 | NSUInteger tCount=[self count]; 21 | 22 | if (tCount>0) 23 | { 24 | NSUInteger tFirstIndex=[self firstIndex]; 25 | NSUInteger tLastIndex=[self lastIndex]; 26 | 27 | return ((tLastIndex-tFirstIndex+1)==tCount); 28 | } 29 | 30 | return NO; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /SaveHollywood/SHAboutBoxWindowController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | @interface SHAboutBoxWindowController : NSWindowController 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SaveHollywood/SHAboutBoxWindowController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHAboutBoxWindowController.h" 15 | 16 | @interface SHAboutBoxWindowController () 17 | { 18 | IBOutlet NSTextField *_versionLabel; 19 | IBOutlet NSTextField *_copyrightLabel; 20 | } 21 | 22 | @end 23 | 24 | @implementation SHAboutBoxWindowController 25 | 26 | - (NSString *)windowNibName 27 | { 28 | return @"SHAboutBoxWindowController"; 29 | } 30 | 31 | - (void)windowDidLoad 32 | { 33 | [super windowDidLoad]; 34 | 35 | NSBundle * tBundle=[NSBundle bundleForClass:[self class]]; 36 | NSDictionary * tInfoDictionary=tBundle.infoDictionary; 37 | 38 | _versionLabel.stringValue=[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"Version %@ (%@)",@"Localized",tBundle,@""),tInfoDictionary[@"CFBundleShortVersionString"],tInfoDictionary[@"CFBundleVersion"]]; 39 | 40 | _copyrightLabel.stringValue=[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"Legal terms",@"Localized",tBundle,@""),[[NSCalendarDate date] yearOfCommonEra]]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SaveHollywood/SHAboutBoxWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1080 5 | 14F2511 6 | 7706 7 | 1348.17 8 | 758.70 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 7706 12 | 13 | 14 | NSCustomObject 15 | NSImageCell 16 | NSImageView 17 | NSTextField 18 | NSTextFieldCell 19 | NSView 20 | NSWindowTemplate 21 | 22 | 23 | com.apple.InterfaceBuilder.CocoaPlugin 24 | 25 | 26 | PluginDependencyRecalculationVersion 27 | 28 | 29 | 30 | 31 | SHAboutBoxWindowController 32 | 33 | 34 | FirstResponder 35 | 36 | 37 | NSApplication 38 | 39 | 40 | 3 41 | 2 42 | {{196, 240}, {314, 181}} 43 | 1618477056 44 | 45 | NSWindow 46 | 47 | 48 | {314, 181} 49 | {314, 181} 50 | 51 | 52 | 256 53 | 54 | 55 | 56 | 268 57 | {{58, 82}, {198, 18}} 58 | 59 | 60 | 61 | _NS:1535 62 | YES 63 | 64 | 68157504 65 | 138413056 66 | SaveHollywood 67 | 68 | YES 69 | 14 70 | 2072 71 | 72 | _NS:1535 73 | 74 | 75 | 6 76 | System 77 | textBackgroundColor 78 | 79 | 3 80 | MQA 81 | 82 | 83 | 84 | 6 85 | System 86 | controlTextColor 87 | 88 | 3 89 | MAA 90 | 91 | 92 | 93 | NO 94 | 1 95 | 96 | 97 | 98 | 268 99 | {{17, 56}, {280, 18}} 100 | 101 | 102 | 103 | _NS:1535 104 | YES 105 | 106 | 68157504 107 | 138413056 108 | Version 109 | 110 | YES 111 | 11 112 | 3100 113 | 114 | _NS:1535 115 | 116 | 117 | 118 | 119 | NO 120 | 1 121 | 122 | 123 | 124 | 268 125 | {{17, 20}, {280, 28}} 126 | 127 | 128 | _NS:1535 129 | YES 130 | 131 | 68157504 132 | 138413056 133 | Q29weXJpZ2h0IMKpIC0yMDEzIFN0w6lwaGFuZSBTdWRyZQpBbGwgcmlnaHRzIHJlc2VydmVkLg 134 | 135 | _NS:1535 136 | 137 | 138 | 139 | 140 | NO 141 | 1 142 | 143 | 144 | 145 | 268 146 | 147 | Apple PDF pasteboard type 148 | Apple PICT pasteboard type 149 | Apple PNG pasteboard type 150 | NSFilenamesPboardType 151 | NeXT Encapsulated PostScript v1.2 pasteboard type 152 | NeXT TIFF v4.0 pasteboard type 153 | 154 | {{112, 110}, {90, 58}} 155 | 156 | 157 | 158 | _NS:9 159 | YES 160 | 161 | 134217728 162 | 33554432 163 | 164 | NSImage 165 | thumbnail 166 | 167 | _NS:9 168 | 0 169 | 0 170 | 0 171 | NO 172 | 173 | NO 174 | YES 175 | 176 | 177 | {314, 181} 178 | 179 | 180 | 181 | 182 | {{0, 0}, {2560, 1577}} 183 | {314, 203} 184 | {314, 203} 185 | NO 186 | 187 | 188 | 189 | 190 | 191 | 192 | window 193 | 194 | 195 | 196 | 3 197 | 198 | 199 | 200 | _copyrightLabel 201 | 202 | 203 | 204 | 45 205 | 206 | 207 | 208 | _versionLabel 209 | 210 | 211 | 212 | 46 213 | 214 | 215 | 216 | delegate 217 | 218 | 219 | 220 | 4 221 | 222 | 223 | 224 | 225 | 226 | 0 227 | 228 | 229 | 230 | 231 | 232 | -2 233 | 234 | 235 | File's Owner 236 | 237 | 238 | -1 239 | 240 | 241 | First Responder 242 | 243 | 244 | -3 245 | 246 | 247 | Application 248 | 249 | 250 | 1 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 2 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 5 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 6 278 | 279 | 280 | 281 | 282 | 9 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 10 291 | 292 | 293 | 294 | 295 | 15 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 16 304 | 305 | 306 | 307 | 308 | 30 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 31 317 | 318 | 319 | 320 | 321 | 322 | 323 | com.apple.InterfaceBuilder.CocoaPlugin 324 | com.apple.InterfaceBuilder.CocoaPlugin 325 | com.apple.InterfaceBuilder.CocoaPlugin 326 | {50, 162.5} 327 | com.apple.InterfaceBuilder.CocoaPlugin 328 | {{357, 418}, {480, 270}} 329 | 330 | com.apple.InterfaceBuilder.CocoaPlugin 331 | com.apple.InterfaceBuilder.CocoaPlugin 332 | com.apple.InterfaceBuilder.CocoaPlugin 333 | com.apple.InterfaceBuilder.CocoaPlugin 334 | com.apple.InterfaceBuilder.CocoaPlugin 335 | com.apple.InterfaceBuilder.CocoaPlugin 336 | com.apple.InterfaceBuilder.CocoaPlugin 337 | com.apple.InterfaceBuilder.CocoaPlugin 338 | com.apple.InterfaceBuilder.CocoaPlugin 339 | 340 | 341 | 342 | 343 | 344 | 46 345 | 346 | 347 | 348 | 349 | SHAboutBoxWindowController 350 | NSWindowController 351 | 352 | IBProjectSource 353 | ../SaveHollywood/SHAboutBoxWindowController.h 354 | 355 | 356 | 357 | SHAboutBoxWindowController 358 | 359 | NSTextField 360 | NSTextField 361 | 362 | 363 | 364 | _copyrightLabel 365 | NSTextField 366 | 367 | 368 | _versionLabel 369 | NSTextField 370 | 371 | 372 | 373 | IBProjectSource 374 | ../SaveHollywood/SHAboutBoxWindowController.m 375 | 376 | 377 | 378 | 379 | 380 | NSActionCell 381 | NSCell 382 | 383 | IBFrameworkSource 384 | AppKit.framework/Headers/NSActionCell.h 385 | 386 | 387 | 388 | NSApplication 389 | NSResponder 390 | 391 | IBFrameworkSource 392 | AppKit.framework/Headers/NSApplication.h 393 | 394 | 395 | 396 | NSCell 397 | NSObject 398 | 399 | IBFrameworkSource 400 | AppKit.framework/Headers/NSCell.h 401 | 402 | 403 | 404 | NSControl 405 | NSView 406 | 407 | IBFrameworkSource 408 | AppKit.framework/Headers/NSControl.h 409 | 410 | 411 | 412 | NSFormatter 413 | NSObject 414 | 415 | IBFrameworkSource 416 | Foundation.framework/Headers/NSFormatter.h 417 | 418 | 419 | 420 | NSImageCell 421 | NSCell 422 | 423 | IBFrameworkSource 424 | AppKit.framework/Headers/NSImageCell.h 425 | 426 | 427 | 428 | NSImageView 429 | NSControl 430 | 431 | IBFrameworkSource 432 | AppKit.framework/Headers/NSImageView.h 433 | 434 | 435 | 436 | NSMenu 437 | NSObject 438 | 439 | IBFrameworkSource 440 | AppKit.framework/Headers/NSMenu.h 441 | 442 | 443 | 444 | NSResponder 445 | NSObject 446 | 447 | IBFrameworkSource 448 | AppKit.framework/Headers/NSResponder.h 449 | 450 | 451 | 452 | NSTextField 453 | NSControl 454 | 455 | IBFrameworkSource 456 | AppKit.framework/Headers/NSTextField.h 457 | 458 | 459 | 460 | NSTextFieldCell 461 | NSActionCell 462 | 463 | IBFrameworkSource 464 | AppKit.framework/Headers/NSTextFieldCell.h 465 | 466 | 467 | 468 | NSView 469 | NSResponder 470 | 471 | IBFrameworkSource 472 | AppKit.framework/Headers/NSView.h 473 | 474 | 475 | 476 | NSWindow 477 | NSResponder 478 | 479 | IBFrameworkSource 480 | AppKit.framework/Headers/NSWindow.h 481 | 482 | 483 | 484 | NSWindowController 485 | NSResponder 486 | 487 | showWindow: 488 | id 489 | 490 | 491 | showWindow: 492 | 493 | showWindow: 494 | id 495 | 496 | 497 | 498 | IBFrameworkSource 499 | AppKit.framework/Headers/NSWindowController.h 500 | 501 | 502 | 503 | 504 | 0 505 | IBCocoaFramework 506 | NO 507 | 508 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 509 | 510 | 511 | YES 512 | 3 513 | 514 | thumbnail 515 | {90, 58} 516 | 517 | 518 | 519 | -------------------------------------------------------------------------------- /SaveHollywood/SHAssetTableCellView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | #import "SHTokenView.h" 17 | 18 | @interface SHAssetTableCellView : NSTableCellView 19 | 20 | @property(assign) IBOutlet SHTokenView *folderAssetsCountLabel; 21 | @property(assign) IBOutlet NSTextField *folderNameLabel; 22 | @property(assign) IBOutlet NSTextField *durationLabel; 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /SaveHollywood/SHAssetTableCellView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHAssetTableCellView.h" 15 | 16 | @interface SHAssetTableCellView() 17 | { 18 | SHTokenView *_folderAssetsCountLabel; 19 | NSTextField *_folderNameLabel; 20 | NSTextField *_durationLabel; 21 | } 22 | 23 | @end 24 | 25 | @implementation SHAssetTableCellView 26 | 27 | @synthesize folderAssetsCountLabel=_folderAssetsCountLabel; 28 | @synthesize folderNameLabel=_folderNameLabel; 29 | @synthesize durationLabel=_durationLabel; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /SaveHollywood/SHConfigurationWindowController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | @interface SHConfigurationWindowController : NSWindowController 17 | 18 | - (void)refreshSettings; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /SaveHollywood/SHConfigurationWindowController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHConfigurationWindowController.h" 15 | 16 | #import 17 | 18 | #import "NSColor+String.h" 19 | #import "NSIndexSet+Analysis.h" 20 | 21 | #import "SHUserDefaults+Constants.h" 22 | 23 | #import 24 | 25 | #import "SHSlider.h" 26 | #import "SHAssetTableCellView.h" 27 | 28 | #import "SHAboutBoxWindowController.h" 29 | 30 | NSString * const SHConfigurationAssetPath=@"Path"; 31 | NSString * const SHConfigurationAssetIcon=@"Icon"; 32 | NSString * const SHConfigurationAssetFolder=@"Folder"; 33 | NSString * const SHConfigurationAssetFolderAssetsCount=@"Count"; 34 | NSString * const SHConfigurationAssetDuration=@"Duration"; 35 | NSString * const SHConfigurationAssetNotFound=@"NotFound"; 36 | 37 | NSString * const SHNotificationAssetPath=@"Path"; 38 | NSString * const SHNotificationAssetDurationString=@"DurationString"; 39 | NSString * const SHNotificationAssetFolderAssetsCount=@"Count"; 40 | 41 | NSString * const SHPasteboardTypeSelectedRows=@"savehollywood.pasterboardType.selectedRows"; 42 | 43 | @interface SHConfigurationWindowController () 44 | { 45 | // UI 46 | 47 | IBOutlet NSButton * _randomOrderCheckBox; 48 | IBOutlet NSButton * _resumePlayingCheckBox; 49 | 50 | IBOutlet NSTableView *_assetsTableView; 51 | 52 | IBOutlet NSButton *_addButton; 53 | IBOutlet NSButton *_deleteButton; 54 | 55 | IBOutlet NSMatrix *_frameScalingMatrix; 56 | IBOutlet NSButton *_frameRandomPositionCheckBox; 57 | 58 | IBOutlet NSButton *_frameDrawBorderCheckBox; 59 | IBOutlet NSButton * _frameShowMetatadaCheckBox; 60 | IBOutlet NSMatrix * _frameShowMetatadaModeMatrix; 61 | IBOutlet SHSlider * _frameShowMetatadaPeriodSlider; 62 | IBOutlet NSTextField * _frameShowMetatadaPeriodLiveValueLabel; 63 | 64 | IBOutlet NSColorWell *_backgroundColorWell; 65 | 66 | IBOutlet NSButton *_audioMainScreenCheckBox; 67 | IBOutlet NSMatrix *_volumeMatrix; 68 | IBOutlet NSButton *_volumeMuteButton; 69 | IBOutlet NSSlider *_volumeSlider; 70 | IBOutlet NSButton *_volumeFullButton; 71 | 72 | IBOutlet NSButton * _mainScreenCheckBox; 73 | 74 | // Data 75 | 76 | NSMutableArray *_cachedAssetsArray; 77 | 78 | NSIndexSet *_internalDragData; 79 | } 80 | 81 | + (NSImage *)createIconForFileType:(NSString *)inFileType; 82 | + (NSImage *)createIconForFile:(NSString *)inPath; 83 | 84 | - (void) updateAssetDuration:(id)inObject; 85 | - (void) updateAssetsCount:(id)inObject; 86 | 87 | - (IBAction)showInFinder:(id)sender; 88 | 89 | - (IBAction)addAsset:(id)sender; 90 | - (IBAction)removeAssets:(id)sender; 91 | 92 | - (IBAction)switchFrameScaling:(id)sender; 93 | 94 | - (IBAction)switchShowMetadata:(id)sender; 95 | - (IBAction)switchShowMetadataMode:(id)sender; 96 | - (IBAction)setPeriodWithSlider:(id)sender; 97 | 98 | - (IBAction)switchVolumeMode:(id)sender; 99 | 100 | - (IBAction)setVolumeMute:(id)sender; 101 | - (IBAction)setVolumeFull:(id)sender; 102 | 103 | - (IBAction)showAboutBox:(id)sender; 104 | 105 | - (IBAction)closeDialog:(id)sender; 106 | 107 | // Notifications 108 | 109 | - (void)shouldShowValueLabel:(NSNotification *)inNotification; 110 | - (void)shouldHideValueLabel:(NSNotification *)inNotification; 111 | 112 | @end 113 | 114 | @implementation SHConfigurationWindowController 115 | 116 | + (NSImage *)createIconForFileType:(NSString *)inFileType 117 | { 118 | NSImage * tImage=[[NSWorkspace sharedWorkspace] iconForFileType:inFileType]; 119 | 120 | [tImage setSize:NSMakeSize(16.,16.)]; 121 | 122 | return tImage; 123 | } 124 | 125 | + (NSImage *)createIconForFile:(NSString *)inPath 126 | { 127 | NSImage * tImage=[[NSWorkspace sharedWorkspace] iconForFile:inPath]; 128 | 129 | [tImage setSize:NSMakeSize(16.,16.)]; 130 | 131 | return tImage; 132 | } 133 | 134 | #pragma mark - 135 | 136 | - (NSString *)windowNibName 137 | { 138 | return @"SHConfigurationWindowController"; 139 | } 140 | 141 | #pragma mark - 142 | 143 | - (void)windowDidLoad 144 | { 145 | [super windowDidLoad]; 146 | 147 | // Set the speaker icons 148 | 149 | NSBundle * tVolumeMenuBundle=[NSBundle bundleWithPath:@"/System/Library/CoreServices/Menu Extras/Volume.menu"]; 150 | 151 | NSURL * tURL=[tVolumeMenuBundle URLForResource:@"Volume1" withExtension:@"pdf"]; 152 | 153 | if (tURL!=nil) 154 | { 155 | NSImage * tImage=[[NSImage alloc] initWithContentsOfURL:tURL]; 156 | 157 | if (tImage!=nil) 158 | { 159 | [tImage setTemplate:YES]; 160 | [_volumeMuteButton setImage:tImage]; 161 | [tImage release]; 162 | } 163 | } 164 | 165 | tURL=[tVolumeMenuBundle URLForResource:@"Volume4" withExtension:@"pdf"]; 166 | 167 | if (tURL!=nil) 168 | { 169 | NSImage * tImage=[[NSImage alloc] initWithContentsOfURL:tURL]; 170 | 171 | if (tImage!=nil) 172 | { 173 | [tImage setTemplate:YES]; 174 | [_volumeFullButton setImage:tImage]; 175 | [tImage release]; 176 | } 177 | } 178 | 179 | // Register for D&D 180 | 181 | [_assetsTableView registerForDraggedTypes:@[SHPasteboardTypeSelectedRows,NSFilenamesPboardType]]; 182 | 183 | [[NSNotificationCenter defaultCenter] addObserver:self 184 | selector:@selector(shouldShowValueLabel:) 185 | name:SHSliderValueDidBeginEditingNotification 186 | object:_frameShowMetatadaPeriodSlider]; 187 | 188 | [[NSNotificationCenter defaultCenter] addObserver:self 189 | selector:@selector(shouldHideValueLabel:) 190 | name:SHSliderValueDidEndEditingNotification 191 | object:_frameShowMetatadaPeriodSlider]; 192 | } 193 | 194 | #pragma mark - 195 | 196 | - (void)refreshSettings 197 | { 198 | #ifdef __TEST_SCREENSAVER__ 199 | NSUserDefaults *tDefaults = [NSUserDefaults standardUserDefaults]; 200 | #else 201 | NSString *tIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier]; 202 | ScreenSaverDefaults *tDefaults = [ScreenSaverDefaults defaultsForModuleWithName:tIdentifier]; 203 | #endif 204 | 205 | float tFloat; 206 | NSColor *tColor=nil; 207 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 208 | 209 | // Assets 210 | 211 | // Random Order 212 | 213 | BOOL tBool=[tDefaults boolForKey:SHUserDefaultsAssetsRandomOrder]; 214 | 215 | [_randomOrderCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 216 | 217 | // Start where left off 218 | 219 | tBool=[tDefaults boolForKey:SHUserDefaultsAssetsStartWhereLeftOff]; 220 | 221 | [_resumePlayingCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 222 | 223 | // List 224 | 225 | _cachedAssetsArray=[[NSMutableArray alloc] initWithCapacity:3]; 226 | 227 | NSArray * tAssetsArray=[tDefaults objectForKey:SHUserDefaultsAssetsLibrary]; 228 | 229 | for(NSString * tPath in tAssetsArray) 230 | { 231 | NSMutableDictionary * tMutableDictionary=[NSMutableDictionary dictionaryWithObject:tPath forKey:SHConfigurationAssetPath]; 232 | BOOL isDirectory; 233 | 234 | if ([tFileManager fileExistsAtPath:tPath isDirectory:&isDirectory]==YES) 235 | { 236 | tMutableDictionary[SHConfigurationAssetFolder]=@(isDirectory); 237 | } 238 | else 239 | { 240 | tMutableDictionary[SHConfigurationAssetNotFound]=@(YES); 241 | } 242 | 243 | [_cachedAssetsArray addObject:tMutableDictionary]; 244 | } 245 | 246 | // Frame 247 | 248 | // Scaling 249 | 250 | NSInteger tInteger=[tDefaults integerForKey:SHUserDefaultsFrameScaling]; 251 | 252 | [_frameScalingMatrix selectCellWithTag:tInteger]; 253 | 254 | [_frameRandomPositionCheckBox setEnabled:(tInteger==kMovieFrameActualSize)]; 255 | 256 | // Random Position 257 | 258 | tBool=[tDefaults boolForKey:SHUserDefaultsFrameRandomPosition]; 259 | 260 | [_frameRandomPositionCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 261 | 262 | // Draw Border 263 | 264 | tBool=[tDefaults boolForKey:SHUserDefaultsFrameDrawBorder]; 265 | 266 | [_frameDrawBorderCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 267 | 268 | // Show Metadata 269 | 270 | tBool=[tDefaults boolForKey:SHUserDefaultsFrameShowMetadata]; 271 | 272 | [_frameShowMetatadaCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 273 | 274 | [_frameShowMetatadaModeMatrix setEnabled:tBool]; 275 | 276 | tInteger=[tDefaults integerForKey:SHUserDefaultsFrameShowMetadataMode]; 277 | 278 | [_frameShowMetatadaModeMatrix selectCellWithTag:tInteger]; 279 | 280 | [_frameShowMetatadaPeriodSlider setEnabled:(tBool==YES && (tInteger==kMovieFrameShowMetadataPeriodically))]; 281 | 282 | 283 | if ([tDefaults objectForKey:SHUserDefaultsFrameShowMetadataPeriod]==nil) 284 | tInteger=SHUserDefaultsFrameShowMetadataPeriodMinimumValue; 285 | else 286 | tInteger=[tDefaults integerForKey:SHUserDefaultsFrameShowMetadataPeriod]; 287 | 288 | [_frameShowMetatadaPeriodSlider setIntegerValue:tInteger]; 289 | [_frameShowMetatadaPeriodLiveValueLabel setStringValue:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"%ld seconds",@"Localized",[NSBundle bundleForClass:[self class]],@""),tInteger]]; 290 | 291 | [_frameShowMetatadaPeriodLiveValueLabel setHidden:YES]; 292 | 293 | // Background Color 294 | 295 | NSString *tString=[tDefaults stringForKey:SHUserDefaultsBackgroundColor]; 296 | 297 | if (tString!=nil) 298 | tColor=[NSColor colorFromString:tString]; 299 | 300 | if (tColor==nil) 301 | tColor=[NSColor blackColor]; 302 | 303 | [_backgroundColorWell setColor:tColor]; 304 | 305 | // Audio 306 | 307 | tBool=[tDefaults boolForKey:SHUserDefaultsAudioMainDisplayOnly]; 308 | 309 | [_audioMainScreenCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 310 | 311 | // Volume 312 | 313 | tInteger=[tDefaults integerForKey:SHUserDefaultsMovieVolumeMode]; 314 | 315 | [_volumeMatrix selectCellWithTag:tInteger]; 316 | 317 | if (tInteger!=kMovieVolumeCustom) 318 | { 319 | [_volumeMuteButton setEnabled:NO]; 320 | [_volumeSlider setEnabled:NO]; 321 | [_volumeFullButton setEnabled:NO]; 322 | } 323 | else 324 | { 325 | [_volumeMuteButton setEnabled:YES]; 326 | [_volumeSlider setEnabled:YES]; 327 | [_volumeFullButton setEnabled:YES]; 328 | } 329 | 330 | id tObject=[tDefaults objectForKey:SHUserDefaultsMovieVolumeCustomValue]; 331 | 332 | if (tObject!=nil) 333 | { 334 | tFloat=[tDefaults floatForKey:SHUserDefaultsMovieVolumeCustomValue]; 335 | [_volumeSlider setFloatValue:tFloat]; 336 | } 337 | 338 | // Main Display Only 339 | 340 | tBool=[tDefaults boolForKey:SHUserDefaultsMainDisplayOnly]; 341 | 342 | [_mainScreenCheckBox setState:(tBool==YES) ? NSOnState : NSOffState]; 343 | 344 | [_assetsTableView reloadData]; 345 | } 346 | 347 | #pragma mark - 348 | 349 | - (void)updateAssetDuration:(id)inObject 350 | { 351 | NSDictionary * tDictionary=(NSDictionary *) inObject; 352 | NSString * tPath=tDictionary[SHNotificationAssetPath]; 353 | 354 | if (tPath==nil) 355 | return; 356 | 357 | for(NSMutableDictionary * tAssetDictionary in _cachedAssetsArray) 358 | { 359 | if ([tAssetDictionary[SHConfigurationAssetPath] isEqualToString:tPath]==YES) 360 | { 361 | tAssetDictionary[SHConfigurationAssetDuration]=tDictionary[SHNotificationAssetDurationString]; 362 | 363 | // Save selection 364 | 365 | NSIndexSet * tSelection=[_assetsTableView selectedRowIndexes]; 366 | 367 | [_assetsTableView reloadData]; 368 | 369 | // Restore selection 370 | 371 | [_assetsTableView selectRowIndexes:tSelection byExtendingSelection:NO]; 372 | 373 | return; 374 | } 375 | } 376 | } 377 | 378 | - (void) getAssetDurationThread:(NSString *)inPath 379 | { 380 | if (inPath==nil) 381 | return; 382 | 383 | NSAutoreleasePool * tPool=[NSAutoreleasePool new]; 384 | 385 | NSURL * tURL=[NSURL fileURLWithPath:inPath]; 386 | 387 | if (tURL!=nil) 388 | { 389 | AVURLAsset *tAVAsset=[AVURLAsset URLAssetWithURL:tURL options:nil]; 390 | 391 | if (tAVAsset!=nil) 392 | { 393 | CMTime tTime=tAVAsset.duration; 394 | Float64 tSeconds=CMTimeGetSeconds(tTime); 395 | 396 | unsigned int tNumberOfHours=tSeconds/(3600.0); 397 | tSeconds=tSeconds-(Float64)tNumberOfHours*3600.0; 398 | 399 | unsigned int tNumberOfMinutes=tSeconds/60.0; 400 | tSeconds=tSeconds-(Float64)tNumberOfMinutes*60.0; 401 | 402 | unsigned int tNumberOfSeconds=tSeconds; 403 | 404 | [self performSelectorOnMainThread:@selector(updateAssetDuration:) 405 | withObject:@{SHNotificationAssetPath:inPath, 406 | SHNotificationAssetDurationString:[NSString stringWithFormat:@"%02u:%02u:%02u",tNumberOfHours,tNumberOfMinutes,tNumberOfSeconds]} 407 | waitUntilDone:NO]; 408 | } 409 | } 410 | 411 | [tPool drain]; 412 | } 413 | 414 | - (void)updateAssetsCount:(id)inObject 415 | { 416 | NSDictionary * tDictionary=(NSDictionary *) inObject; 417 | NSString * tPath=tDictionary[SHNotificationAssetPath]; 418 | 419 | if (tPath==nil) 420 | return; 421 | 422 | for(NSMutableDictionary * tAssetDictionary in _cachedAssetsArray) 423 | { 424 | if ([tAssetDictionary[SHConfigurationAssetPath] isEqualToString:tPath]==YES) 425 | { 426 | tAssetDictionary[SHConfigurationAssetFolderAssetsCount]=tDictionary[SHNotificationAssetFolderAssetsCount]; 427 | 428 | // Save selection 429 | 430 | NSIndexSet * tSelection=[_assetsTableView selectedRowIndexes]; 431 | 432 | [_assetsTableView reloadData]; 433 | 434 | // Restore selection 435 | 436 | [_assetsTableView selectRowIndexes:tSelection byExtendingSelection:NO]; 437 | 438 | return; 439 | } 440 | } 441 | } 442 | 443 | - (void)getAssetsCountThread:(NSString *)inPath 444 | { 445 | if (inPath==nil) 446 | return; 447 | 448 | NSAutoreleasePool * tPool=[NSAutoreleasePool new]; 449 | 450 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 451 | NSUInteger tCount=0; 452 | BOOL isDirectory; 453 | 454 | if ([tFileManager fileExistsAtPath:inPath isDirectory:&isDirectory]==YES && isDirectory==YES) 455 | { 456 | NSArray * tArray=[tFileManager contentsOfDirectoryAtPath:inPath error:NULL]; 457 | NSArray * tUTIsArray=[AVURLAsset audiovisualTypes]; 458 | 459 | for(NSString * tFileName in tArray) 460 | { 461 | NSString * tFilePath=[inPath stringByAppendingPathComponent:tFileName]; 462 | 463 | if ([tFileManager fileExistsAtPath:tFilePath isDirectory:&isDirectory]==YES && isDirectory==NO) 464 | { 465 | NSString * tFileUTI; 466 | NSURL * tURL=[NSURL fileURLWithPath:tFilePath]; 467 | 468 | if ([tURL getResourceValue:&tFileUTI forKey:NSURLTypeIdentifierKey error:NULL]==YES) 469 | { 470 | if ([tUTIsArray containsObject:tFileUTI]==YES) 471 | { 472 | AVURLAsset *tAVAsset=[AVURLAsset URLAssetWithURL:tURL options:nil]; 473 | 474 | if (tAVAsset.isPlayable==YES) 475 | tCount++; 476 | } 477 | } 478 | } 479 | } 480 | } 481 | 482 | [self performSelectorOnMainThread:@selector(updateAssetsCount:) 483 | withObject:@{SHNotificationAssetPath:inPath, 484 | SHNotificationAssetFolderAssetsCount:@(tCount)} 485 | waitUntilDone:NO]; 486 | 487 | [tPool drain]; 488 | } 489 | 490 | #pragma mark - 491 | 492 | - (BOOL)validateMenuItem:(NSMenuItem *)inMenuItem 493 | { 494 | SEL tAction=[inMenuItem action]; 495 | 496 | if (tAction==@selector(showInFinder:)) 497 | { 498 | NSInteger tClickedRow=[_assetsTableView clickedRow]; 499 | 500 | if (tClickedRow!=-1) 501 | { 502 | NSIndexSet * tIndexSet=[_assetsTableView selectedRowIndexes]; 503 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 504 | 505 | if ([tIndexSet containsIndex:tClickedRow]==NO) 506 | { 507 | NSDictionary * tDictionary=_cachedAssetsArray[tClickedRow]; 508 | 509 | NSString * tAssetPath=tDictionary[SHConfigurationAssetPath]; 510 | 511 | if (tAssetPath!=nil) 512 | return [tFileManager fileExistsAtPath:tAssetPath]; 513 | } 514 | else 515 | { 516 | NSUInteger tCount=[tIndexSet count]; 517 | 518 | for(NSDictionary * tDictionary in [_cachedAssetsArray objectsAtIndexes:tIndexSet]) 519 | { 520 | NSString * tAssetPath=tDictionary[SHConfigurationAssetPath]; 521 | 522 | if (tAssetPath!=nil) 523 | { 524 | if ([tFileManager fileExistsAtPath:tAssetPath]==NO) 525 | tCount--; 526 | } 527 | } 528 | 529 | return (tCount>0); 530 | } 531 | } 532 | } 533 | 534 | return YES; 535 | } 536 | 537 | - (IBAction)showInFinder:(id)sender 538 | { 539 | NSInteger tClickedRow=[_assetsTableView clickedRow]; 540 | 541 | if (tClickedRow==-1) 542 | return; 543 | 544 | NSIndexSet * tIndexSet=[_assetsTableView selectedRowIndexes]; 545 | 546 | if ([tIndexSet containsIndex:tClickedRow]==NO) 547 | { 548 | NSDictionary * tDictionary=_cachedAssetsArray[tClickedRow]; 549 | NSString * tAssetPath=tDictionary[SHConfigurationAssetPath]; 550 | 551 | if (tAssetPath!=nil) 552 | [[NSWorkspace sharedWorkspace] selectFile:tAssetPath inFileViewerRootedAtPath:@""]; 553 | } 554 | else 555 | { 556 | for(NSDictionary * tDictionary in [_cachedAssetsArray objectsAtIndexes:tIndexSet]) 557 | { 558 | NSString * tAssetPath=tDictionary[SHConfigurationAssetPath]; 559 | 560 | if (tAssetPath!=nil) 561 | [[NSWorkspace sharedWorkspace] selectFile:tAssetPath inFileViewerRootedAtPath:@""]; 562 | } 563 | } 564 | } 565 | 566 | - (IBAction)addAsset:(id)sender 567 | { 568 | NSOpenPanel *tOpenPanel; 569 | 570 | tOpenPanel=[NSOpenPanel openPanel]; 571 | 572 | [tOpenPanel setDelegate:self]; 573 | [tOpenPanel setCanChooseDirectories:YES]; 574 | [tOpenPanel setAllowsMultipleSelection:YES]; 575 | [tOpenPanel setAllowedFileTypes:[AVURLAsset audiovisualTypes]]; 576 | [tOpenPanel setTitle:NSLocalizedStringFromTableInBundle(@"Add video or folder",@"Localized",[NSBundle bundleForClass:[self class]],@"")]; 577 | [tOpenPanel setPrompt:NSLocalizedStringFromTableInBundle(@"Add",@"Localized",[NSBundle bundleForClass:[self class]],@"")]; 578 | 579 | NSInteger tResult=[tOpenPanel runModal]; 580 | 581 | if (tResult==NSFileHandlingPanelOKButton) 582 | { 583 | NSArray * tURLs=[tOpenPanel URLs]; 584 | NSMutableIndexSet * tMutableIndexSet=[NSMutableIndexSet indexSet]; 585 | NSUInteger tCount=[_cachedAssetsArray count]; 586 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 587 | 588 | for(NSURL * tURL in tURLs) 589 | { 590 | if ([tURL isFileURL]==YES) 591 | { 592 | NSString * tPath=[tURL path]; 593 | BOOL tFound=NO; 594 | 595 | NSMutableDictionary * tMutableDictionary=[NSMutableDictionary dictionaryWithObject:tPath forKey:SHConfigurationAssetPath]; 596 | BOOL isDirectory; 597 | 598 | if ([tFileManager fileExistsAtPath:tPath isDirectory:&isDirectory]==YES) 599 | tMutableDictionary[SHConfigurationAssetFolder]=@(isDirectory); 600 | else 601 | tMutableDictionary[SHConfigurationAssetNotFound]=@(YES); 602 | 603 | for(NSDictionary * tAssetDictionary in _cachedAssetsArray) 604 | { 605 | NSString * tAssetPath=tAssetDictionary[SHConfigurationAssetPath]; 606 | 607 | if ([tAssetPath caseInsensitiveCompare:tPath]==NSOrderedSame) 608 | { 609 | tFound=YES; 610 | break; 611 | } 612 | } 613 | 614 | if (tFound==NO) 615 | { 616 | [_cachedAssetsArray addObject:tMutableDictionary]; 617 | 618 | [tMutableIndexSet addIndex:tCount]; 619 | tCount++; 620 | } 621 | } 622 | } 623 | 624 | if ([tMutableIndexSet count]>0) 625 | { 626 | [_assetsTableView reloadData]; 627 | 628 | [_assetsTableView selectRowIndexes:tMutableIndexSet byExtendingSelection:NO]; 629 | } 630 | } 631 | } 632 | 633 | - (IBAction)removeAssets:(id)sender 634 | { 635 | NSIndexSet * tIndexSet=[_assetsTableView selectedRowIndexes]; 636 | 637 | [_cachedAssetsArray removeObjectsAtIndexes:tIndexSet]; 638 | 639 | [_assetsTableView deselectAll:nil]; 640 | 641 | [_assetsTableView reloadData]; 642 | } 643 | 644 | - (IBAction)switchFrameScaling:(id)sender 645 | { 646 | [_frameRandomPositionCheckBox setEnabled:([[sender selectedCell] tag]==kMovieFrameActualSize)]; 647 | } 648 | 649 | - (IBAction)switchShowMetadata:(id)sender 650 | { 651 | BOOL tBool=([sender state]==NSOnState); 652 | NSInteger tTag=[[_frameShowMetatadaModeMatrix selectedCell] tag]; 653 | 654 | [_frameShowMetatadaModeMatrix setEnabled:tBool]; 655 | 656 | [_frameShowMetatadaPeriodSlider setEnabled:tBool && (tTag==kMovieFrameShowMetadataPeriodically)]; 657 | } 658 | 659 | - (IBAction)switchShowMetadataMode:(id)sender 660 | { 661 | NSInteger tTag=[[sender selectedCell] tag]; 662 | 663 | [_frameShowMetatadaPeriodSlider setEnabled:(tTag==kMovieFrameShowMetadataPeriodically)]; 664 | } 665 | 666 | - (IBAction)setPeriodWithSlider:(id)sender 667 | { 668 | [_frameShowMetatadaPeriodLiveValueLabel setStringValue:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"%ld seconds",@"Localized",[NSBundle bundleForClass:[self class]],@""),[sender integerValue]]]; 669 | } 670 | 671 | - (IBAction)switchVolumeMode:(id)sender 672 | { 673 | BOOL tEnabled=([[sender selectedCell] tag]==kMovieVolumeCustom); 674 | 675 | [_volumeMuteButton setEnabled:tEnabled]; 676 | [_volumeSlider setEnabled:tEnabled]; 677 | [_volumeFullButton setEnabled:tEnabled]; 678 | } 679 | 680 | - (IBAction)setVolumeMute:(id)sender 681 | { 682 | [_volumeSlider setFloatValue:0.0f]; 683 | } 684 | 685 | - (IBAction)setVolumeFull:(id)sender 686 | { 687 | [_volumeSlider setFloatValue:1.0f]; 688 | } 689 | 690 | - (IBAction)showAboutBox:(id)sender 691 | { 692 | static SHAboutBoxWindowController * sAboutBoxWindowController=nil; 693 | 694 | if (sAboutBoxWindowController==nil) 695 | sAboutBoxWindowController=[SHAboutBoxWindowController new]; 696 | 697 | if ([sAboutBoxWindowController.window isVisible]==NO) 698 | [sAboutBoxWindowController.window center]; 699 | 700 | [sAboutBoxWindowController.window makeKeyAndOrderFront:nil]; 701 | } 702 | 703 | - (IBAction)closeDialog:(id)sender 704 | { 705 | if ([sender tag]==NSOKButton) 706 | { 707 | #ifdef __TEST_SCREENSAVER__ 708 | NSUserDefaults *tDefaults = [NSUserDefaults standardUserDefaults]; 709 | #else 710 | NSString *tIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier]; 711 | ScreenSaverDefaults *tDefaults = [ScreenSaverDefaults defaultsForModuleWithName:tIdentifier]; 712 | #endif 713 | NSString *tString; 714 | 715 | // Assets 716 | 717 | // Random Order 718 | 719 | [tDefaults setBool:([_randomOrderCheckBox state]==NSOnState) forKey:SHUserDefaultsAssetsRandomOrder]; 720 | 721 | // Start where left off 722 | 723 | [tDefaults setBool:([_resumePlayingCheckBox state]==NSOnState) forKey:SHUserDefaultsAssetsStartWhereLeftOff]; 724 | 725 | // List 726 | 727 | NSMutableArray * tAssetsArray=[NSMutableArray array]; 728 | 729 | for(NSDictionary * tAssetDictionary in _cachedAssetsArray) 730 | { 731 | NSString * tAssetPath=tAssetDictionary[SHConfigurationAssetPath]; 732 | 733 | if (tAssetPath!=nil) 734 | [tAssetsArray addObject:tAssetPath]; 735 | } 736 | 737 | [tDefaults setObject:tAssetsArray 738 | forKey:SHUserDefaultsAssetsLibrary]; 739 | 740 | // Frame 741 | 742 | // Scaling 743 | 744 | NSInteger tInteger=[[_frameScalingMatrix selectedCell] tag]; 745 | 746 | [tDefaults setInteger:tInteger forKey:SHUserDefaultsFrameScaling]; 747 | 748 | // Random Position 749 | 750 | [tDefaults setBool:([_frameRandomPositionCheckBox state]==NSOnState) forKey:SHUserDefaultsFrameRandomPosition]; 751 | 752 | // Draw Border 753 | 754 | [tDefaults setBool:([_frameDrawBorderCheckBox state]==NSOnState) forKey:SHUserDefaultsFrameDrawBorder]; 755 | 756 | // Show Metadata 757 | 758 | [tDefaults setBool:([_frameShowMetatadaCheckBox state]==NSOnState) forKey:SHUserDefaultsFrameShowMetadata]; 759 | 760 | // Show Metadata mode 761 | 762 | tInteger=[[_frameShowMetatadaModeMatrix selectedCell] tag]; 763 | 764 | [tDefaults setInteger:tInteger forKey:SHUserDefaultsFrameShowMetadataMode]; 765 | 766 | if (tInteger==kMovieFrameShowMetadataPeriodically) 767 | [tDefaults setInteger:[_frameShowMetatadaPeriodSlider integerValue] forKey:SHUserDefaultsFrameShowMetadataPeriod]; 768 | 769 | // Color 770 | 771 | NSColor *tColor=[_backgroundColorWell color]; 772 | 773 | if (tColor!=nil) 774 | { 775 | tString=[tColor stringValue]; 776 | 777 | if (tString!=nil) 778 | [tDefaults setObject:tString forKey:SHUserDefaultsBackgroundColor]; 779 | } 780 | 781 | // Audio 782 | 783 | [tDefaults setBool:([_audioMainScreenCheckBox state]==NSOnState) forKey:SHUserDefaultsAudioMainDisplayOnly]; 784 | 785 | // Volume 786 | 787 | tInteger=[[_volumeMatrix selectedCell] tag]; 788 | 789 | [tDefaults setInteger:tInteger forKey:SHUserDefaultsMovieVolumeMode]; 790 | 791 | if (tInteger==kMovieVolumeCustom) 792 | [tDefaults setFloat:[_volumeSlider floatValue] forKey:SHUserDefaultsMovieVolumeCustomValue]; 793 | 794 | // Main Screen Only 795 | 796 | [tDefaults setBool:([_mainScreenCheckBox state]==NSOnState) forKey:SHUserDefaultsMainDisplayOnly]; 797 | 798 | [tDefaults synchronize]; 799 | } 800 | 801 | [_assetsTableView deselectAll:nil]; 802 | 803 | [NSApp endSheet:self.window]; 804 | } 805 | 806 | #pragma mark - NSTableView DataSource 807 | 808 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)inTableView 809 | { 810 | if (inTableView==_assetsTableView) 811 | return [_cachedAssetsArray count]; 812 | 813 | return 0; 814 | } 815 | 816 | - (NSView *)tableView:(NSTableView *)inTableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)inRow 817 | { 818 | if (inTableView==_assetsTableView) 819 | { 820 | SHAssetTableCellView * tAssetTableView = [inTableView makeViewWithIdentifier:@"AssetView" owner:self]; 821 | 822 | NSMutableDictionary * tAssetDictionary=_cachedAssetsArray[inRow]; 823 | 824 | NSNumber * tNumber=tAssetDictionary[SHConfigurationAssetNotFound]; 825 | 826 | if (tNumber==nil) 827 | { 828 | // Icon 829 | 830 | NSImage * tIcon=tAssetDictionary[SHConfigurationAssetIcon]; 831 | 832 | if (tIcon==nil) 833 | { 834 | tIcon=[[NSWorkspace sharedWorkspace] iconForFile:tAssetDictionary[SHConfigurationAssetPath]]; 835 | 836 | if (tIcon!=nil) 837 | tAssetDictionary[SHConfigurationAssetIcon]=tIcon; 838 | } 839 | 840 | if ([tAssetDictionary[SHConfigurationAssetFolder] boolValue]==YES) 841 | { 842 | [tAssetTableView.textField setHidden:YES]; 843 | [tAssetTableView.durationLabel setHidden:YES]; 844 | [tAssetTableView.folderNameLabel setHidden:NO]; 845 | [tAssetTableView.folderAssetsCountLabel setHidden:NO]; 846 | 847 | [tAssetTableView.folderNameLabel setStringValue:[tAssetDictionary[SHConfigurationAssetPath] lastPathComponent]]; 848 | 849 | [tAssetTableView.folderNameLabel setTextColor:[NSColor blackColor]]; 850 | 851 | tAssetTableView.imageView.image=tIcon; 852 | 853 | // Number of assets at first level of folder 854 | 855 | NSNumber * tNumber=tAssetDictionary[SHConfigurationAssetFolderAssetsCount]; 856 | 857 | if (tNumber==nil) 858 | { 859 | [tAssetTableView.folderAssetsCountLabel setStringValue:@"-"]; 860 | 861 | [NSThread detachNewThreadSelector:@selector(getAssetsCountThread:) toTarget:self withObject:tAssetDictionary[SHConfigurationAssetPath]]; 862 | } 863 | else 864 | { 865 | [tAssetTableView.folderAssetsCountLabel setUnsignedIntegerValue:[tNumber unsignedIntegerValue]]; 866 | } 867 | } 868 | else 869 | { 870 | [tAssetTableView.textField setHidden:NO]; 871 | [tAssetTableView.durationLabel setHidden:NO]; 872 | [tAssetTableView.folderNameLabel setHidden:YES]; 873 | [tAssetTableView.folderAssetsCountLabel setHidden:YES]; 874 | 875 | [tAssetTableView.textField setStringValue:[tAssetDictionary[SHConfigurationAssetPath] lastPathComponent]]; 876 | 877 | tAssetTableView.imageView.image=tIcon; 878 | 879 | // Duration 880 | 881 | NSString * tString=tAssetDictionary [SHConfigurationAssetDuration]; 882 | 883 | if (tString==nil) 884 | { 885 | // Find the duration in a detached thread 886 | 887 | [tAssetTableView.durationLabel setStringValue:@"--:--:--"]; 888 | 889 | [NSThread detachNewThreadSelector:@selector(getAssetDurationThread:) toTarget:self withObject:tAssetDictionary[SHConfigurationAssetPath]]; 890 | } 891 | else 892 | { 893 | [tAssetTableView.durationLabel setStringValue:tString]; 894 | } 895 | } 896 | } 897 | else 898 | { 899 | [tAssetTableView.textField setHidden:YES]; 900 | [tAssetTableView.durationLabel setHidden:YES]; 901 | [tAssetTableView.folderNameLabel setHidden:NO]; 902 | [tAssetTableView.folderAssetsCountLabel setHidden:YES]; 903 | 904 | [tAssetTableView.folderNameLabel setStringValue:[tAssetDictionary[SHConfigurationAssetPath] lastPathComponent]]; 905 | 906 | [tAssetTableView.folderNameLabel setTextColor:[NSColor redColor]]; 907 | 908 | tAssetTableView.imageView.image=[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUnknownFSObjectIcon)]; 909 | } 910 | 911 | return tAssetTableView; 912 | } 913 | 914 | return nil; 915 | } 916 | 917 | - (BOOL)tableView:(NSTableView *)inTableView writeRowsWithIndexes:(NSIndexSet *)inIndexSet toPasteboard:(NSPasteboard *)inPasteboard 918 | { 919 | if (inTableView==_assetsTableView) 920 | { 921 | if ([inIndexSet count]>0) 922 | { 923 | [inPasteboard declareTypes:[NSArray arrayWithObject:SHPasteboardTypeSelectedRows] owner:nil]; 924 | 925 | [_internalDragData release]; 926 | _internalDragData=[inIndexSet retain]; 927 | 928 | [inPasteboard setData:[NSData data] forType:SHPasteboardTypeSelectedRows]; 929 | 930 | return YES; 931 | } 932 | } 933 | 934 | return NO; 935 | } 936 | 937 | - (NSDragOperation)tableView:(NSTableView *)inTableView validateDrop:(id )inDraggingInfo proposedRow:(NSInteger)inRow proposedDropOperation:(NSTableViewDropOperation)inDropOperation 938 | { 939 | if (inTableView==_assetsTableView && inDropOperation==NSTableViewDropAbove) 940 | { 941 | NSPasteboard * tPasteboard=[inDraggingInfo draggingPasteboard]; 942 | NSString * tPasteboardType=[tPasteboard availableTypeFromArray:@[SHPasteboardTypeSelectedRows,NSFilenamesPboardType]]; 943 | 944 | if ([tPasteboardType isEqualToString:SHPasteboardTypeSelectedRows]==YES) 945 | { 946 | if ([_internalDragData containsOnlyOneRange]==YES) 947 | { 948 | NSUInteger tFirstIndex=[_internalDragData firstIndex]; 949 | NSUInteger tLastIndex=[_internalDragData lastIndex]; 950 | 951 | if (inRow>=tFirstIndex && inRow<=(tLastIndex+1)) 952 | return NSDragOperationNone; 953 | } 954 | else 955 | { 956 | if ([_internalDragData containsIndex:(inRow-1)]==YES) 957 | return NSDragOperationNone; 958 | } 959 | 960 | return NSDragOperationMove; 961 | } 962 | else if ([tPasteboardType isEqualToString:NSFilenamesPboardType]==YES) 963 | { 964 | // Check whether the files can be accepted (same as Open panel in 2 steps) 965 | 966 | NSArray * tFilesArray = [tPasteboard propertyListForType:NSFilenamesPboardType]; 967 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 968 | NSWorkspace * tSharedWorkspace=[NSWorkspace sharedWorkspace]; 969 | NSArray * tAcceptedUTIsArray=[AVURLAsset audiovisualTypes]; 970 | BOOL tFoundAtLeastOne=NO; 971 | 972 | for (NSString * tFile in tFilesArray) 973 | { 974 | // Check that the path is not already in the list 975 | 976 | BOOL tFound=NO; 977 | 978 | for(NSDictionary * tAssetDictionary in _cachedAssetsArray) 979 | { 980 | NSString * tAssetPath=tAssetDictionary[SHConfigurationAssetPath]; 981 | 982 | if ([tAssetPath caseInsensitiveCompare:tFile]==NSOrderedSame) 983 | { 984 | tFound=YES; 985 | break; 986 | } 987 | } 988 | 989 | if (tFound==NO) 990 | { 991 | BOOL isDirectory; 992 | 993 | if ([tFileManager fileExistsAtPath:tFile isDirectory:&isDirectory]==YES) 994 | { 995 | if (isDirectory==YES) 996 | { 997 | tFoundAtLeastOne=YES; 998 | break; 999 | } 1000 | else 1001 | { 1002 | NSString * tUTI=[tSharedWorkspace typeOfFile:tFile error:NULL]; 1003 | 1004 | if (tUTI!=nil) 1005 | { 1006 | if ([tAcceptedUTIsArray containsObject:tUTI]==YES) 1007 | { 1008 | tFoundAtLeastOne=YES; 1009 | break; 1010 | } 1011 | } 1012 | } 1013 | } 1014 | } 1015 | } 1016 | 1017 | if (tFoundAtLeastOne==YES) 1018 | return NSDragOperationCopy; 1019 | } 1020 | } 1021 | 1022 | return NSDragOperationNone; 1023 | } 1024 | 1025 | - (BOOL)tableView:(NSTableView *)inTableView acceptDrop:(id )inDraggingInfo row:(NSInteger)inRow dropOperation:(NSTableViewDropOperation)inDropOperation 1026 | { 1027 | if (inTableView==_assetsTableView) 1028 | { 1029 | NSMutableArray * tNewAssets=nil; 1030 | 1031 | NSPasteboard * tPasteboard=[inDraggingInfo draggingPasteboard]; 1032 | NSString * tPasteboardType=[tPasteboard availableTypeFromArray:@[SHPasteboardTypeSelectedRows,NSFilenamesPboardType]]; 1033 | 1034 | if ([tPasteboardType isEqualToString:SHPasteboardTypeSelectedRows]==YES) 1035 | { 1036 | NSUInteger tIndex=[_internalDragData firstIndex]; 1037 | 1038 | tNewAssets=[[[_cachedAssetsArray objectsAtIndexes:_internalDragData] mutableCopy] autorelease]; 1039 | 1040 | while (tIndex!=NSNotFound) 1041 | { 1042 | if (tIndex0) 1112 | { 1113 | [_cachedAssetsArray insertObjects:tNewAssets 1114 | atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(inRow,tCount)]]; 1115 | 1116 | [_assetsTableView reloadData]; 1117 | 1118 | // Update selection 1119 | 1120 | [_assetsTableView selectRowIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(inRow,tCount)] 1121 | byExtendingSelection:NO]; 1122 | 1123 | return YES; 1124 | } 1125 | else 1126 | { 1127 | NSBeep(); 1128 | } 1129 | } 1130 | 1131 | return NO; 1132 | } 1133 | 1134 | #pragma mark - NSSavePanel delegate 1135 | 1136 | - (BOOL)panel:(id)sender validateURL:(NSURL *)inURL error:(NSError **)outError 1137 | { 1138 | if ([inURL isFileURL]==YES) 1139 | { 1140 | NSFileManager * tFileManager=[NSFileManager defaultManager]; 1141 | BOOL tIsDirectory; 1142 | 1143 | if ([tFileManager fileExistsAtPath:[inURL path] isDirectory:&tIsDirectory]==YES && tIsDirectory==YES) 1144 | return YES; 1145 | } 1146 | 1147 | AVURLAsset *tAVAsset=[AVURLAsset URLAssetWithURL:inURL options:nil]; 1148 | 1149 | if (tAVAsset.isPlayable==NO) 1150 | { 1151 | // A COMPLETER 1152 | 1153 | return NO; 1154 | } 1155 | 1156 | return YES; 1157 | } 1158 | 1159 | #pragma mark - Notifications 1160 | 1161 | - (void)tableViewSelectionDidChange:(NSNotification *)inNotification 1162 | { 1163 | [_deleteButton setEnabled:[_assetsTableView numberOfSelectedRows]>0]; 1164 | } 1165 | 1166 | - (void)shouldShowValueLabel:(NSNotification *)inNotification 1167 | { 1168 | [_frameShowMetatadaPeriodLiveValueLabel setHidden:NO]; 1169 | } 1170 | 1171 | - (void)shouldHideValueLabel:(NSNotification *)inNotification 1172 | { 1173 | [_frameShowMetatadaPeriodLiveValueLabel setHidden:YES]; 1174 | } 1175 | 1176 | @end 1177 | -------------------------------------------------------------------------------- /SaveHollywood/SHLightGrayBackgroundView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024 Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHView.h" 15 | 16 | @interface SHLightGrayBackgroundView : SHView 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SaveHollywood/SHLightGrayBackgroundView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHLightGrayBackgroundView.h" 15 | 16 | @implementation SHLightGrayBackgroundView 17 | 18 | - (BOOL)isOpaque 19 | { 20 | return NO; 21 | } 22 | 23 | #pragma mark - 24 | 25 | - (void)drawRect:(NSRect)dirtyRect 26 | { 27 | if ([self isEffectiveAppareanceDarkAqua]==YES) 28 | return; 29 | 30 | [[NSColor colorWithDeviceWhite:0.915 alpha:0.8] set]; 31 | 32 | NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver); 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /SaveHollywood/SHPlayingAssetsRegister.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface SHPlayingAssetsRegister : NSObject 4 | 5 | + (SHPlayingAssetsRegister *)sharedRegister; 6 | 7 | @property (readonly,nonatomic) NSArray * allPlayingAssets; 8 | 9 | - (BOOL)isPlayingAsset:(id)inAsset; 10 | 11 | - (void)addAsset:(id)inAsset; 12 | - (void)removeAsset:(id)inAsset; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /SaveHollywood/SHPlayingAssetsRegister.m: -------------------------------------------------------------------------------- 1 | #import "SHPlayingAssetsRegister.h" 2 | 3 | @interface SHPlayingAssetsRegister () 4 | { 5 | NSMutableSet * _playingAssetsSet; 6 | 7 | NSLock * _lock; 8 | } 9 | 10 | @end 11 | 12 | @implementation SHPlayingAssetsRegister 13 | 14 | + (SHPlayingAssetsRegister *)sharedRegister 15 | { 16 | static SHPlayingAssetsRegister * sPlayingAssetsRegister=nil; 17 | static dispatch_once_t onceToken; 18 | 19 | dispatch_once(&onceToken, ^{ 20 | sPlayingAssetsRegister=[SHPlayingAssetsRegister new]; 21 | }); 22 | 23 | return sPlayingAssetsRegister; 24 | } 25 | 26 | - (instancetype)init 27 | { 28 | self=[super init]; 29 | 30 | if (self!=nil) 31 | { 32 | _playingAssetsSet=[[NSMutableSet alloc] init]; 33 | 34 | _lock=[NSLock new]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | #pragma mark - 41 | 42 | - (NSArray *)allPlayingAssets 43 | { 44 | NSArray * tAllPlayingAssets=[NSArray array]; 45 | 46 | [_lock lock]; 47 | 48 | tAllPlayingAssets=[_playingAssetsSet allObjects]; 49 | 50 | [_lock unlock]; 51 | 52 | return tAllPlayingAssets; 53 | } 54 | 55 | #pragma mark - 56 | 57 | - (BOOL)isPlayingAsset:(id)inAsset 58 | { 59 | if (inAsset==nil) 60 | return NO; 61 | 62 | BOOL tIsPlaying=NO; 63 | 64 | [_lock lock]; 65 | 66 | tIsPlaying=[_playingAssetsSet containsObject:inAsset]; 67 | 68 | [_lock unlock]; 69 | 70 | return tIsPlaying; 71 | } 72 | 73 | - (void)addAsset:(id)inAsset 74 | { 75 | if (inAsset==nil) 76 | return; 77 | 78 | [_lock lock]; 79 | 80 | [_playingAssetsSet addObject:inAsset]; 81 | 82 | [_lock unlock]; 83 | } 84 | 85 | - (void)removeAsset:(id)inAsset 86 | { 87 | if (inAsset==nil) 88 | return; 89 | 90 | [_lock lock]; 91 | 92 | [_playingAssetsSet removeObject:inAsset]; 93 | 94 | [_lock unlock]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /SaveHollywood/SHSecondaryBox.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHView.h" 15 | 16 | @interface SHSecondaryBox : SHView 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SaveHollywood/SHSecondaryBox.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHSecondaryBox.h" 15 | 16 | @implementation SHSecondaryBox 17 | 18 | - (BOOL)isOpaque 19 | { 20 | return NO; 21 | } 22 | 23 | #pragma mark - 24 | 25 | - (void)drawRect:(NSRect)dirtyRect 26 | { 27 | if ([self isEffectiveAppareanceDarkAqua]==NO) 28 | [[NSColor colorWithDeviceWhite:1.0 alpha:0.5] set]; 29 | else 30 | [[NSColor colorWithDeviceWhite:0.0 alpha:0.15] set]; 31 | 32 | NSRectFillUsingOperation(dirtyRect,NSCompositeSourceOver); 33 | 34 | [[NSColor colorWithDeviceWhite:0.0 alpha:0.10] set]; 35 | 36 | NSRect tFrameRect=NSInsetRect([self bounds],-1,0); 37 | 38 | NSFrameRectWithWidthUsingOperation(tFrameRect, 1.0, NSCompositeSourceOver); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /SaveHollywood/SHSettings.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | typedef NS_ENUM(NSUInteger, SHMovieScaling) 5 | { 6 | SHMovieScaleProportionallyUpOrDown=0, // Scale movie to maximum possible dimensions while (1) staying within destination area (2) preserving aspect ratio 7 | SHMovieScaleAxesIndependently, // Scale each dimension to exactly fit destination. Do not preserve aspect ratio. 8 | SHMovieScaleNone, // Do not scale. 9 | }; 10 | 11 | enum { 12 | kMovieFrameShowMetadataAtStart=0, 13 | kMovieFrameShowMetadataPeriodically 14 | }; 15 | 16 | typedef NS_ENUM(NSUInteger, SHMovieAudioVolumeMode) 17 | { 18 | SHMovieAudioVolumeNormal=0, 19 | SHMovieAudioVolumeMute, 20 | SHMovieAudioVolumeCustom 21 | }; 22 | 23 | #define SHUserDefaultsFrameShowMetadataPeriodMinimumValue 15 24 | #define SHUserDefaultsFrameShowMetadataPeriodMaximumValue 60 25 | 26 | @interface SHSettings : NSObject 27 | 28 | @property BOOL randomOrder; 29 | @property BOOL startWhereLeftOff; 30 | 31 | @property (retain) NSMutableArray * assets; 32 | 33 | @property SHMovieScaling scaling; 34 | @property BOOL randomPosition; 35 | 36 | @property BOOL drawBorder; 37 | @property BOOL showMetadata; 38 | @property NSInteger showMetadataMode; 39 | @property NSInteger showMetadataPeriod; 40 | 41 | @property (copy) NSColor * backgroundColor; 42 | 43 | @property BOOL audioMainScreenOnly; 44 | @property SHMovieAudioVolumeMode audioMode; 45 | @property CGFloat audioVolume; 46 | 47 | @property BOOL mainDisplayOnly; 48 | 49 | + (SHSettings *)settings; 50 | 51 | + (BOOL)isConfigurationLocked; 52 | 53 | - (instancetype)initWithDictionaryRepresentation:(NSDictionary *)inDictionary; 54 | 55 | - (NSDictionary *)dictionaryRepresentation; 56 | 57 | - (void)resetSettings; 58 | 59 | 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SaveHollywood/SHSettings.m: -------------------------------------------------------------------------------- 1 | 2 | #import "SHSettings.h" 3 | 4 | #ifndef __TEST_SCREENSAVER__ 5 | #import 6 | #endif 7 | 8 | #import "NSColor+String.h" 9 | 10 | NSString * const SHUserDefaultsAssetsRandomOrder=@"assets.randomOrder"; 11 | NSString * const SHUserDefaultsAssetsStartWhereLeftOff=@"assets.startWhereLeftOff"; 12 | NSString * const SHUserDefaultsAssetsLibrary=@"assets.library"; 13 | 14 | NSString * const SHUserDefaultsFrameScaling=@"frame.scaling"; 15 | NSString * const SHUserDefaultsFrameRandomPosition=@"frame.randomPosition"; 16 | 17 | NSString * const SHUserDefaultsFrameDrawBorder=@"frame.drawBorder"; 18 | NSString * const SHUserDefaultsFrameShowMetadata=@"frame.showMetadata"; 19 | NSString * const SHUserDefaultsFrameShowMetadataMode=@"frame.showMetadata.mode"; 20 | NSString * const SHUserDefaultsFrameShowMetadataPeriod=@"frame.showMetadata.period"; 21 | 22 | 23 | NSString * const SHUserDefaultsBackgroundColor=@"frame.background.color"; 24 | 25 | NSString * const SHUserDefaultsAudioMainDisplayOnly=@"movie.audio.mainDisplayOnly"; 26 | 27 | NSString * const SHUserDefaultsMovieVolumeMode=@"movie.volume.mode"; 28 | 29 | NSString * const SHUserDefaultsMovieVolumeCustomValue=@"movie.volume.value"; 30 | 31 | NSString * const SHUserDefaultsMainDisplayOnly=@"screen.mainDisplayOnly"; 32 | 33 | NSString * const SHSharedLockUserDefaultsRepresentationPath=@"/Library/Preferences/fr.whitebox.SaveHollywood.locked.plist"; 34 | 35 | static BOOL sSettingsAreLocked=NO; 36 | 37 | @implementation SHSettings 38 | 39 | + (SHSettings *)settings 40 | { 41 | NSDictionary * tRepresentation=[NSDictionary dictionaryWithContentsOfFile:SHSharedLockUserDefaultsRepresentationPath]; 42 | 43 | if (tRepresentation==nil) 44 | { 45 | sSettingsAreLocked=NO; 46 | 47 | #ifdef __TEST_SCREENSAVER__ 48 | NSUserDefaults *tDefaults = [NSUserDefaults standardUserDefaults]; 49 | #else 50 | NSString *tIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier]; 51 | ScreenSaverDefaults *tDefaults = [ScreenSaverDefaults defaultsForModuleWithName:tIdentifier]; 52 | #endif 53 | 54 | tRepresentation=[tDefaults dictionaryRepresentation]; 55 | } 56 | else 57 | { 58 | sSettingsAreLocked=YES; 59 | } 60 | 61 | return [[[SHSettings alloc] initWithDictionaryRepresentation:tRepresentation] autorelease]; 62 | } 63 | 64 | + (BOOL)isConfigurationLocked 65 | { 66 | return [[NSFileManager defaultManager] fileExistsAtPath:SHSharedLockUserDefaultsRepresentationPath]; 67 | } 68 | 69 | - (instancetype)initWithDictionaryRepresentation:(NSDictionary *)inDictionary 70 | { 71 | self=[super init]; 72 | 73 | if (self!=nil) 74 | { 75 | id tValue=inDictionary[SHUserDefaultsAssetsRandomOrder]; 76 | 77 | if (tValue==nil) 78 | { 79 | [self resetSettings]; 80 | } 81 | else 82 | { 83 | _randomOrder=[inDictionary[SHUserDefaultsAssetsRandomOrder] boolValue]; 84 | _startWhereLeftOff=[inDictionary[SHUserDefaultsAssetsStartWhereLeftOff] boolValue]; 85 | 86 | NSArray * tArray=inDictionary[SHUserDefaultsAssetsLibrary]; 87 | 88 | if (tArray==nil) 89 | tArray=@[]; 90 | 91 | _assets=[tArray mutableCopy]; 92 | 93 | _scaling=[inDictionary[SHUserDefaultsFrameScaling] integerValue]; 94 | _randomPosition=[inDictionary[SHUserDefaultsFrameRandomPosition] boolValue]; 95 | 96 | _drawBorder=[inDictionary[SHUserDefaultsFrameDrawBorder] boolValue]; 97 | _showMetadata=[inDictionary[SHUserDefaultsFrameShowMetadata] boolValue]; 98 | _showMetadataMode=[inDictionary[SHUserDefaultsFrameShowMetadataMode] integerValue]; 99 | _showMetadataPeriod=[inDictionary[SHUserDefaultsFrameShowMetadataPeriod] integerValue]; 100 | 101 | NSString * tString=inDictionary[SHUserDefaultsBackgroundColor];; 102 | 103 | if (tString!=nil) 104 | _backgroundColor=[[NSColor colorFromString:tString] copy]; 105 | 106 | if (_backgroundColor==nil) 107 | _backgroundColor=[NSColor blackColor]; 108 | 109 | _audioMainScreenOnly=[inDictionary[SHUserDefaultsAudioMainDisplayOnly] boolValue]; 110 | _audioMode=[inDictionary[SHUserDefaultsMovieVolumeMode] integerValue]; 111 | _audioVolume=[inDictionary[SHUserDefaultsMovieVolumeCustomValue] integerValue]; 112 | 113 | 114 | _mainDisplayOnly=[inDictionary[SHUserDefaultsMainDisplayOnly] boolValue]; 115 | } 116 | 117 | return self; 118 | } 119 | 120 | return nil; 121 | } 122 | 123 | - (NSDictionary *)dictionaryRepresentation 124 | { 125 | NSMutableDictionary * tMutableDictionary=[NSMutableDictionary dictionary]; 126 | 127 | if (tMutableDictionary!=nil) 128 | { 129 | tMutableDictionary[SHUserDefaultsAssetsRandomOrder]=@(self.randomOrder); 130 | tMutableDictionary[SHUserDefaultsAssetsStartWhereLeftOff]=@(self.startWhereLeftOff); 131 | 132 | tMutableDictionary[SHUserDefaultsAssetsLibrary]=[[self.assets copy] autorelease]; 133 | 134 | tMutableDictionary[SHUserDefaultsFrameScaling]=@(self.scaling); 135 | tMutableDictionary[SHUserDefaultsFrameRandomPosition]=@(self.randomPosition); 136 | 137 | tMutableDictionary[SHUserDefaultsFrameDrawBorder]=@(self.drawBorder); 138 | tMutableDictionary[SHUserDefaultsFrameShowMetadata]=@(self.showMetadata); 139 | tMutableDictionary[SHUserDefaultsFrameShowMetadataMode]=@(self.showMetadataMode); 140 | tMutableDictionary[SHUserDefaultsFrameShowMetadataPeriod]=@(self.showMetadataPeriod); 141 | 142 | tMutableDictionary[SHUserDefaultsBackgroundColor]=[self.backgroundColor stringValue]; 143 | 144 | tMutableDictionary[SHUserDefaultsAudioMainDisplayOnly]=@(self.audioMainScreenOnly); 145 | tMutableDictionary[SHUserDefaultsMovieVolumeMode]=@(self.audioMode); 146 | tMutableDictionary[SHUserDefaultsMovieVolumeCustomValue]=@(self.audioVolume); 147 | 148 | tMutableDictionary[SHUserDefaultsMainDisplayOnly]=@(self.mainDisplayOnly); 149 | } 150 | 151 | return [tMutableDictionary copy]; 152 | } 153 | 154 | - (void)resetSettings 155 | { 156 | self.randomOrder=NO; 157 | self.startWhereLeftOff=NO; 158 | 159 | self.assets=[NSMutableArray array]; 160 | 161 | self.scaling=SHMovieScaleProportionallyUpOrDown; 162 | self.randomPosition=NO; 163 | 164 | self.drawBorder=NO; 165 | self.showMetadata=NO; 166 | self.showMetadataMode=kMovieFrameShowMetadataAtStart; 167 | self.showMetadataPeriod=SHUserDefaultsFrameShowMetadataPeriodMinimumValue; 168 | 169 | self.backgroundColor=[NSColor blackColor]; 170 | 171 | self.audioMainScreenOnly=NO; 172 | self.audioMode=SHMovieAudioVolumeNormal; 173 | self.audioVolume=1.0; 174 | 175 | self.mainDisplayOnly=NO; 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /SaveHollywood/SHSlider.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | extern NSString * const SHSliderValueDidBeginEditingNotification; 17 | extern NSString * const SHSliderValueDidEndEditingNotification; 18 | 19 | @interface SHSlider : NSSlider 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /SaveHollywood/SHSlider.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHSlider.h" 15 | 16 | NSString * const SHSliderValueDidBeginEditingNotification=@"SHSliderValueDidBeginEditingNotification"; 17 | NSString * const SHSliderValueDidEndEditingNotification=@"SHSliderValueDidEndEditingNotification"; 18 | 19 | @implementation SHSlider 20 | 21 | - (void)mouseDown:(NSEvent *)inEvent 22 | { 23 | if ([self isEnabled]==YES) 24 | { 25 | [[NSNotificationCenter defaultCenter] postNotificationName:SHSliderValueDidBeginEditingNotification 26 | object:self]; 27 | } 28 | 29 | [super mouseDown:inEvent]; 30 | 31 | if ([self isEnabled]==YES) 32 | { 33 | [[NSNotificationCenter defaultCenter] postNotificationName:SHSliderValueDidEndEditingNotification 34 | object:self]; 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /SaveHollywood/SHTokenView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | @interface SHTokenView : NSView 17 | { 18 | } 19 | 20 | - (void)setStringValue:(NSString *)inValue; 21 | - (void)setUnsignedIntegerValue:(NSUInteger)inValue; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /SaveHollywood/SHTokenView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHTokenView.h" 15 | 16 | @interface SHTokenView () 17 | { 18 | NSDictionary *_attributesDictionary; 19 | NSAttributedString * _cachedStringValue; 20 | } 21 | @end 22 | 23 | CGFloat heightForStringDrawing(NSAttributedString *myString, CGFloat myWidth) 24 | { 25 | NSTextStorage *textStorage = [[[NSTextStorage alloc] initWithAttributedString:myString] autorelease]; 26 | NSTextContainer *textContainer = [[[NSTextContainer alloc] initWithContainerSize: NSMakeSize(myWidth, FLT_MAX)] autorelease]; 27 | NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init] autorelease]; 28 | 29 | [layoutManager addTextContainer:textContainer]; 30 | [textStorage addLayoutManager:layoutManager]; 31 | [textContainer setLineFragmentPadding:0.0]; 32 | 33 | (void) [layoutManager glyphRangeForTextContainer:textContainer]; 34 | return [layoutManager usedRectForTextContainer:textContainer].size.height; 35 | } 36 | 37 | @implementation SHTokenView 38 | 39 | - (id)initWithFrame:(NSRect)frameRect 40 | { 41 | self=[super initWithFrame:frameRect]; 42 | 43 | if (self!=nil) 44 | { 45 | NSMutableParagraphStyle * tMutableParagraphStyle=[[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 46 | tMutableParagraphStyle.alignment=NSCenterTextAlignment; 47 | 48 | NSShadow * tShadow=[NSShadow new]; 49 | tShadow.shadowOffset=NSMakeSize(0,-1); 50 | tShadow.shadowColor=[NSColor colorWithDeviceWhite:0.65 alpha:1.0]; 51 | 52 | _attributesDictionary=[@{NSForegroundColorAttributeName:[NSColor whiteColor], 53 | NSFontAttributeName:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]], 54 | NSParagraphStyleAttributeName:tMutableParagraphStyle, 55 | NSShadowAttributeName:tShadow} copy]; 56 | 57 | 58 | [tMutableParagraphStyle release]; 59 | [tShadow release]; 60 | } 61 | 62 | return self; 63 | } 64 | 65 | - (void)dealloc 66 | { 67 | [_attributesDictionary release]; 68 | 69 | [super dealloc]; 70 | } 71 | 72 | - (void)setStringValue:(NSString *)inValue 73 | { 74 | [_cachedStringValue release]; 75 | 76 | _cachedStringValue=[[NSAttributedString alloc] initWithString:inValue 77 | attributes:_attributesDictionary]; 78 | } 79 | 80 | - (void)setUnsignedIntegerValue:(NSUInteger)inValue 81 | { 82 | [self setStringValue:[NSString stringWithFormat:@"%lu",inValue]]; 83 | } 84 | 85 | #pragma mark - 86 | 87 | - (void)drawRect:(NSRect)dirtyRect 88 | { 89 | NSRect tBounds=[self bounds]; 90 | 91 | // Draw background 92 | 93 | CGFloat tRadius=NSHeight(tBounds)*0.5; 94 | NSBezierPath * tBezierPath=[NSBezierPath bezierPathWithRoundedRect:tBounds xRadius:tRadius yRadius:tRadius]; 95 | 96 | [[NSColor colorWithDeviceWhite:0.88 alpha:1.0] setFill]; 97 | 98 | [tBezierPath fill]; 99 | 100 | // Draw value 101 | 102 | if (_cachedStringValue!=nil) 103 | { 104 | CGFloat tHeight=[NSFont systemFontSizeForControlSize:NSRegularControlSize];//heightForStringDrawing(_cachedStringValue,tBounds.size.width); 105 | 106 | tBounds.origin.y=round(NSMidY(tBounds)-tHeight*0.5+1); 107 | tBounds.size.height=tHeight; 108 | 109 | [_cachedStringValue drawWithRect:tBounds options:0]; 110 | } 111 | } 112 | @end 113 | -------------------------------------------------------------------------------- /SaveHollywood/SHUserDefaults+Constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | extern NSString * const SHUserDefaultsAssetsRandomOrder; 17 | extern NSString * const SHUserDefaultsAssetsStartWhereLeftOff; 18 | extern NSString * const SHUserDefaultsAssetsLibrary; 19 | 20 | 21 | enum { 22 | kMovieFrameSizeToFit=0, 23 | kMovieFrameSizeToFill, 24 | kMovieFrameActualSize 25 | }; 26 | 27 | extern NSString * const SHUserDefaultsFrameScaling; 28 | extern NSString * const SHUserDefaultsFrameRandomPosition; 29 | 30 | extern NSString * const SHUserDefaultsFrameDrawBorder; 31 | extern NSString * const SHUserDefaultsFrameShowMetadata; 32 | 33 | enum { 34 | kMovieFrameShowMetadataAtStart=0, 35 | kMovieFrameShowMetadataPeriodically 36 | }; 37 | 38 | extern NSString * const SHUserDefaultsFrameShowMetadataMode; 39 | 40 | #define SHUserDefaultsFrameShowMetadataPeriodMinimumValue 15 41 | #define SHUserDefaultsFrameShowMetadataPeriodMaximumValue 60 42 | 43 | extern NSString * const SHUserDefaultsFrameShowMetadataPeriod; 44 | 45 | extern NSString * const SHUserDefaultsBackgroundColor; 46 | 47 | extern NSString * const SHUserDefaultsAudioMainDisplayOnly; 48 | 49 | enum { 50 | kMovieVolumeNormal=0, 51 | kMovieVolumeMute, 52 | kMovieVolumeCustom 53 | }; 54 | 55 | extern NSString * const SHUserDefaultsMovieVolumeMode; 56 | extern NSString * const SHUserDefaultsMovieVolumeCustomValue; 57 | 58 | extern NSString * const SHUserDefaultsMainDisplayOnly; 59 | -------------------------------------------------------------------------------- /SaveHollywood/SHUserDefaults+Constants.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHUserDefaults+Constants.h" 15 | -------------------------------------------------------------------------------- /SaveHollywood/SHView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import 15 | 16 | @interface SHView : NSView 17 | 18 | - (BOOL)isEffectiveAppareanceDarkAqua; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /SaveHollywood/SHView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SHView.h" 15 | 16 | #ifndef NSAppKitVersionNumber10_14 17 | #define NSAppKitVersionNumber10_14 1641.10 18 | #endif 19 | 20 | @implementation SHView 21 | 22 | - (BOOL)isEffectiveAppareanceDarkAqua 23 | { 24 | if (NSAppKitVersionNumber 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | fr.whitebox.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 2.6 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 10 25 | NSHumanReadableCopyright 26 | Copyright © 2013-2018 WhiteBox. All rights reserved. 27 | NSPrincipalClass 28 | SaveHollywoodView 29 | NSRequiresAquaSystemAppearance 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SaveHollywood/SaveHollywood-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'SaveHollywood' target in the 'SaveHollywood' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | 9 | #ifndef NSAppKitVersionNumber10_14 10 | #define NSAppKitVersionNumber10_14 1641.10 11 | #endif -------------------------------------------------------------------------------- /SaveHollywood/SaveHollywoodView.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #ifdef __TEST_SCREENSAVER__ 15 | #import 16 | #else 17 | #import 18 | #endif 19 | 20 | #import 21 | 22 | #ifdef __TEST_SCREENSAVER__ 23 | @interface SaveHollywoodView : NSView 24 | #else 25 | @interface SaveHollywoodView : ScreenSaverView 26 | #endif 27 | @end 28 | -------------------------------------------------------------------------------- /SaveHollywood/SaveHollywoodView.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2024, Stephane Sudre 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | - Neither the name of the WhiteBox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | */ 13 | 14 | #import "SaveHollywoodView.h" 15 | #import "SHConfigurationWindowController.h" 16 | 17 | //#import "SHUserDefaults+Constants.h" 18 | 19 | #import "SHSettings.h" 20 | 21 | #import "SHPlayingAssetsRegister.h" 22 | 23 | #import "NSColor+String.h" 24 | #import "NSArray+Shuffle.h" 25 | 26 | #define BORDER_SIZE 50.0 27 | 28 | #define LRAND() ((long) (random() & 0x7fffffff)) 29 | #define MAXRAND (2147483648.0) /* unsigned 1<<31 as a float */ 30 | 31 | #define METADATA_DISPLAY_DURATION 5.0 32 | 33 | NSString * const SHScreenKey=@"screen#"; 34 | NSString * const SHScreenKeyKeyed=@"screen.keyed#"; 35 | NSString * const SHAssetTimeKey=@"asset.time"; 36 | NSString * const SHAssetURLKey=@"asset.url"; 37 | 38 | NSString * const SHShouldSwitchMutedStateNotification=@"SHShouldSwitchMutedStateNotification"; 39 | NSString * const SHShouldIncreaseVolumeNotification=@"SHShouldIncreaseVolumeNotification"; 40 | NSString * const SHShouldDecreaseVolumeNotification=@"SHShouldDecreaseVolumeNotification"; 41 | 42 | NSUInteger random_no(NSUInteger); 43 | 44 | NSUInteger random_no(NSUInteger n) 45 | { 46 | return ((NSUInteger) ((n + 1) * (double) LRAND() / MAXRAND)); 47 | } 48 | 49 | @interface SaveHollywoodView () 50 | { 51 | // Data 52 | 53 | NSFileManager * _fileManager; 54 | BOOL _preview; 55 | BOOL _mainScreen; 56 | 57 | SHMovieScaling _scaling; 58 | BOOL _randomPosition; 59 | 60 | BOOL _drawBorder; 61 | BOOL _showMetadata; 62 | NSInteger _metadadataMode; 63 | NSInteger _metadadataPeriod; 64 | 65 | NSTimer * _timer; 66 | BOOL _liveMuted; 67 | BOOL _volumeLevelHasBeenModified; 68 | 69 | BOOL _audioMainScreen; 70 | SHMovieAudioVolumeMode _volumeMode; 71 | float _volumeLevel; 72 | 73 | // Workaround for Apple bug in Sierra 74 | 75 | BOOL _useKeyedArchiverForLeftOffData; 76 | 77 | // Layers 78 | 79 | CALayer * _backgroundLayer; 80 | AVPlayerLayer * _AVPlayerLayer; 81 | CALayer * _metadataLayer; 82 | 83 | // Assets iteration 84 | 85 | BOOL _randomOrder; 86 | 87 | NSUInteger __arrayIndex; 88 | NSMutableArray * __assetsArray; 89 | 90 | // Current Asset 91 | 92 | NSString *_currentAssetMetadataTitle; 93 | NSString *_currentAssetMetadataCopyrights; 94 | 95 | // Preferences 96 | 97 | SHConfigurationWindowController *_configurationWindowController; 98 | } 99 | 100 | - (NSUInteger)screenIndex; 101 | 102 | - (BOOL)playNextAsset:(NSDictionary *)preferredNextAssetDictionary canPlaySameRandomMovieTwice:(BOOL)inCanPlaySameRandomMovieTwice; 103 | 104 | - (void)switchMutedState:(NSNotification *)inNotification; 105 | - (void)increaseVolume:(NSNotificationCenter *)inNotification; 106 | - (void)decreaseVolume:(NSNotificationCenter *)inNotification; 107 | 108 | - (void)showMetadata:(NSTimer *)inTimer; 109 | - (void)hideMetadata:(id)object; 110 | 111 | 112 | 113 | @end 114 | 115 | @implementation SaveHollywoodView 116 | 117 | #pragma mark - 118 | 119 | #ifdef __TEST_SCREENSAVER__ 120 | 121 | - (id)initWithFrame:(NSRect)frameRect 122 | { 123 | self=[super initWithFrame:frameRect]; 124 | 125 | if (self!=nil) 126 | { 127 | _fileManager=[NSFileManager defaultManager]; 128 | 129 | _preview=NO; 130 | 131 | if (_preview==YES) 132 | { 133 | _mainScreen=YES; 134 | } 135 | else 136 | { 137 | _mainScreen= (NSMinX(frameRect)==0 && NSMinY(frameRect)==0); 138 | } 139 | 140 | [self setWantsLayer:YES]; 141 | } 142 | 143 | return self; 144 | } 145 | 146 | #else 147 | 148 | - (id)initWithFrame:(NSRect)frameRect isPreview:(BOOL)isPreview 149 | { 150 | self=[super initWithFrame:frameRect isPreview:isPreview]; 151 | 152 | if (self!=nil) 153 | { 154 | SInt32 tMajorVersion,tMinorVersion,tBugFixVersion; 155 | 156 | Gestalt(gestaltSystemVersionMajor,&tMajorVersion); 157 | Gestalt(gestaltSystemVersionMinor,&tMinorVersion); 158 | Gestalt(gestaltSystemVersionBugFix,&tBugFixVersion); 159 | 160 | 161 | _useKeyedArchiverForLeftOffData=(tMajorVersion>10 || (tMajorVersion==10 && tMinorVersion>=12)); 162 | 163 | [self setAnimationTimeInterval:1.0]; 164 | 165 | _fileManager=[NSFileManager defaultManager]; 166 | 167 | _preview=isPreview; 168 | 169 | if (_preview==YES) 170 | { 171 | _mainScreen=YES; 172 | } 173 | else 174 | { 175 | _mainScreen= (NSMinX(frameRect)==0 && NSMinY(frameRect)==0); 176 | } 177 | 178 | [self setWantsLayer:YES]; 179 | } 180 | 181 | return self; 182 | } 183 | 184 | #endif 185 | 186 | #pragma mark - 187 | 188 | - (void)keyDown:(NSEvent *) inEvent 189 | { 190 | if (_preview==NO) 191 | { 192 | BOOL tCanChangeVolume=(_volumeMode!=SHMovieAudioVolumeMute); 193 | 194 | NSString * tString=[inEvent characters]; 195 | NSUInteger tLength=[tString length]; 196 | 197 | for(NSUInteger tIndex=0;tIndex1.0f) 359 | { 360 | _volumeLevel=1.0f; 361 | } 362 | 363 | // Assets 364 | 365 | // Random Order 366 | 367 | _randomOrder=tSettings.randomOrder; 368 | 369 | // List 370 | 371 | __arrayIndex=0; 372 | 373 | NSArray * tDefaultsArray=tSettings.assets; 374 | 375 | NSMutableArray * tAssets=[NSMutableArray array]; 376 | 377 | for(NSString * tPath in tDefaultsArray) 378 | { 379 | NSURL * tURL=[NSURL fileURLWithPath:tPath]; 380 | 381 | if (tURL!=nil) 382 | { 383 | [tAssets addObject:tURL]; 384 | } 385 | } 386 | 387 | if ([tAssets count]>0) 388 | { 389 | __assetsArray=[[NSMutableArray alloc] initWithCapacity:[tAssets count]]; 390 | 391 | if (__assetsArray!=nil) 392 | { 393 | // Flatten the list of potential assets and prune it from incompatible and unplayable files 394 | NSArray * tAcceptedUTIsArray=[AVURLAsset audiovisualTypes]; 395 | NSWorkspace * tSharedWorkspace=[NSWorkspace sharedWorkspace]; 396 | 397 | for(NSURL * tURL in tAssets) 398 | { 399 | if ([tURL isFileURL]==YES) 400 | { 401 | NSString * tAbsolutePath=[tURL path]; 402 | BOOL tIsDirectory; 403 | 404 | if ([_fileManager fileExistsAtPath:tAbsolutePath isDirectory:&tIsDirectory]==YES) 405 | { 406 | if (tIsDirectory==NO) 407 | { 408 | // Check that the file is of a supported type 409 | 410 | NSString * tUTI=[tSharedWorkspace typeOfFile:tAbsolutePath error:NULL]; 411 | 412 | if (tUTI!=nil && [tAcceptedUTIsArray containsObject:tUTI]==YES) 413 | { 414 | [__assetsArray addObject:tURL]; 415 | } 416 | } 417 | else 418 | { 419 | NSError *tError=nil; 420 | 421 | // Add the contents of the directory 422 | 423 | NSArray * tFileNamesArray=[_fileManager contentsOfDirectoryAtPath:tAbsolutePath error:&tError]; 424 | 425 | if (tFileNamesArray==nil) 426 | { 427 | NSLog(@"Unable to get the contents of the directory at path \"%@\"",tAbsolutePath); 428 | } 429 | else 430 | { 431 | for (NSString * tFileName in tFileNamesArray) 432 | { 433 | NSString * tSubPath=[tAbsolutePath stringByAppendingPathComponent:tFileName]; 434 | 435 | // Check that the file is of a supported type 436 | 437 | NSString * tUTI=[tSharedWorkspace typeOfFile:tSubPath error:NULL]; 438 | 439 | if (tUTI!=nil && [tAcceptedUTIsArray containsObject:tUTI]==YES) 440 | { 441 | NSURL *tSubURL=[NSURL fileURLWithPath:tSubPath]; 442 | 443 | if (tSubURL!=nil) 444 | { 445 | [__assetsArray addObject:tSubURL]; 446 | } 447 | } 448 | } 449 | } 450 | } 451 | } 452 | } 453 | else 454 | { 455 | // Remote URL 456 | 457 | // A COMPLETER 458 | } 459 | } 460 | 461 | NSUInteger tCount=[__assetsArray count]; 462 | 463 | if (tCount>0) 464 | { 465 | if (tCount>1) 466 | { 467 | if (_randomOrder==YES) 468 | { 469 | // Shuffle Array 470 | 471 | [__assetsArray shuffle]; 472 | } 473 | } 474 | 475 | // Add observer 476 | 477 | [[NSNotificationCenter defaultCenter] addObserver:self 478 | selector:@selector(playerItemDidPlayToEnd:) 479 | name:AVPlayerItemDidPlayToEndTimeNotification 480 | object:nil]; 481 | 482 | // 483 | 484 | NSDictionary * tLastKnownAssetDictionary=nil; 485 | 486 | if (_preview==NO) 487 | { 488 | NSUInteger tScreenIndex=[self screenIndex]; 489 | 490 | if (tScreenIndex!=NSNotFound) 491 | { 492 | NSString * tScreenKey; 493 | 494 | if (_useKeyedArchiverForLeftOffData==YES) 495 | tScreenKey=[NSString stringWithFormat:@"%@%lu",SHScreenKeyKeyed,(unsigned long)tScreenIndex]; 496 | else 497 | tScreenKey=[NSString stringWithFormat:@"%@%lu",SHScreenKey,(unsigned long)tScreenIndex]; 498 | 499 | if (tSettings.startWhereLeftOff==YES) 500 | { 501 | NSData * tData=[tDefaults objectForKey:tScreenKey]; 502 | 503 | if (tData!=nil) 504 | { 505 | if (_useKeyedArchiverForLeftOffData==YES) 506 | tLastKnownAssetDictionary=[NSKeyedUnarchiver unarchiveObjectWithData:tData]; 507 | else 508 | tLastKnownAssetDictionary=[NSUnarchiver unarchiveObjectWithData:tData]; 509 | 510 | if (tLastKnownAssetDictionary==nil) 511 | NSLog(@"Error when unarchiving last known asset for %@",tScreenKey); 512 | } 513 | } 514 | else 515 | { 516 | [tDefaults removeObjectForKey:tScreenKey]; 517 | } 518 | } 519 | } 520 | 521 | // Play the next asset 522 | 523 | if ([self playNextAsset:tLastKnownAssetDictionary canPlaySameRandomMovieTwice:NO]==YES) 524 | { 525 | return; 526 | } 527 | } 528 | } 529 | } 530 | 531 | // No playable asset available => Display text 532 | 533 | CGRect tBackgroundFrame=_backgroundLayer.bounds; 534 | CGRect tFrame; 535 | 536 | CATextLayer * tWarningTextLayer=[CATextLayer layer]; 537 | 538 | tWarningTextLayer.font=@"Lucida Grande Bold"; 539 | tWarningTextLayer.alignmentMode=kCAAlignmentCenter; 540 | tWarningTextLayer.foregroundColor=CGColorGetConstantColor(kCGColorWhite); 541 | 542 | if (_preview==YES) 543 | { 544 | tWarningTextLayer.fontSize=16; 545 | 546 | tFrame=CGRectInset(tBackgroundFrame,20.,0); 547 | 548 | tFrame.origin.y=CGRectGetMidY(tBackgroundFrame)-9.0; 549 | tFrame.size.height=20.; 550 | } 551 | else 552 | { 553 | tWarningTextLayer.fontSize=35; 554 | 555 | tFrame=CGRectInset(tBackgroundFrame,20.,0); 556 | 557 | tFrame.origin.y=CGRectGetMidY(tBackgroundFrame)-18.0; 558 | tFrame.size.height=35.; 559 | } 560 | 561 | tWarningTextLayer.frame=tFrame; 562 | 563 | tWarningTextLayer.string=NSLocalizedStringFromTableInBundle(@"No videos",@"Localized",[NSBundle bundleForClass:[self class]],@""); 564 | 565 | [_backgroundLayer addSublayer:tWarningTextLayer]; 566 | } 567 | } 568 | } 569 | 570 | - (void)stopAnimation 571 | { 572 | #ifdef __TEST_SCREENSAVER__ 573 | NSUserDefaults *tDefaults = [NSUserDefaults standardUserDefaults]; 574 | #else 575 | NSString *tIdentifier = [[NSBundle bundleForClass:[self class]] bundleIdentifier]; 576 | ScreenSaverDefaults *tDefaults = [ScreenSaverDefaults defaultsForModuleWithName:tIdentifier]; 577 | #endif 578 | 579 | SHSettings * tSettings=[SHSettings settings]; 580 | 581 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideMetadata:) object:nil]; 582 | 583 | // Remove observers 584 | 585 | [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; 586 | 587 | [[NSNotificationCenter defaultCenter] removeObserver:self name:SHShouldIncreaseVolumeNotification object:nil]; 588 | [[NSNotificationCenter defaultCenter] removeObserver:self name:SHShouldDecreaseVolumeNotification object:nil]; 589 | [[NSNotificationCenter defaultCenter] removeObserver:self name:SHShouldSwitchMutedStateNotification object:nil]; 590 | 591 | // Stop Movie 592 | 593 | if (_preview==NO) 594 | { 595 | // Save current asset and time if necessary 596 | 597 | NSUInteger tScreenIndex=[self screenIndex]; 598 | 599 | if (tScreenIndex!=NSNotFound) 600 | { 601 | NSString * tScreenKey; 602 | 603 | if (_useKeyedArchiverForLeftOffData==YES) 604 | tScreenKey=[NSString stringWithFormat:@"%@%lu",SHScreenKeyKeyed,(unsigned long)tScreenIndex]; 605 | else 606 | tScreenKey=[NSString stringWithFormat:@"%@%lu",SHScreenKey,(unsigned long)tScreenIndex]; 607 | 608 | if (tSettings.startWhereLeftOff==YES) 609 | { 610 | NSURL * tCurrentURL=[((AVURLAsset *) _AVPlayerLayer.player.currentItem.asset) URL]; 611 | 612 | if (tCurrentURL!=nil) 613 | { 614 | CMTime tCurrentTime=[_AVPlayerLayer.player currentTime]; 615 | NSValue * tValue=[NSValue valueWithCMTime:tCurrentTime]; 616 | 617 | NSDictionary * tLastAssetDictionary=@{SHAssetTimeKey:tValue, 618 | SHAssetURLKey:tCurrentURL}; 619 | 620 | NSData * tData=nil; 621 | 622 | if (_useKeyedArchiverForLeftOffData==YES) 623 | tData=[NSKeyedArchiver archivedDataWithRootObject:tLastAssetDictionary]; 624 | else 625 | tData=[NSArchiver archivedDataWithRootObject:tLastAssetDictionary]; 626 | 627 | if (tData!=nil) 628 | [tDefaults setObject:tData forKey:tScreenKey]; 629 | } 630 | } 631 | else 632 | { 633 | [tDefaults removeObjectForKey:tScreenKey]; 634 | } 635 | 636 | [tDefaults synchronize]; // Workaround for bug introduced by Apple in Yosemite 637 | } 638 | } 639 | 640 | [_currentAssetMetadataTitle release]; 641 | _currentAssetMetadataTitle=nil; 642 | 643 | [_currentAssetMetadataCopyrights release]; 644 | _currentAssetMetadataCopyrights=nil; 645 | 646 | [_AVPlayerLayer.player pause]; 647 | 648 | [[SHPlayingAssetsRegister sharedRegister] removeAsset:((AVURLAsset *)_AVPlayerLayer.player.currentItem.asset).URL]; 649 | 650 | if (_timer!=nil) 651 | { 652 | [_timer invalidate]; 653 | 654 | [_timer release]; 655 | _timer=nil; 656 | } 657 | 658 | _AVPlayerLayer=nil; 659 | [_backgroundLayer removeFromSuperlayer]; 660 | 661 | _metadataLayer=nil; 662 | _backgroundLayer=nil; 663 | 664 | [__assetsArray release]; 665 | __assetsArray=nil; 666 | 667 | __arrayIndex=0; 668 | 669 | _liveMuted=NO; 670 | _volumeLevelHasBeenModified=NO; 671 | 672 | #ifndef __TEST_SCREENSAVER__ 673 | [super stopAnimation]; 674 | #endif 675 | } 676 | 677 | - (BOOL)playNextAsset:(NSDictionary *)preferredNextAssetDictionary canPlaySameRandomMovieTwice:(BOOL)inCanPlaySameRandomMovieTwice 678 | { 679 | NSUInteger tCount=[__assetsArray count]; 680 | AVURLAsset * tAsset=nil; 681 | NSUInteger tNextIndex=__arrayIndex; 682 | NSURL * tPreferredNextURL=preferredNextAssetDictionary[SHAssetURLKey]; 683 | 684 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideMetadata:) object:nil]; 685 | 686 | if (_timer!=nil) 687 | { 688 | [_timer invalidate]; 689 | 690 | [_timer release]; 691 | 692 | _timer=nil; 693 | } 694 | 695 | if (__arrayIndex>=tCount) 696 | { 697 | __arrayIndex=0; 698 | } 699 | 700 | while (__arrayIndex0 || tPreferredNextURL!=nil) 779 | { 780 | // We at least played once asset previously (or we were looking for the last known asset) 781 | 782 | __arrayIndex=0; 783 | 784 | return [self playNextAsset:nil canPlaySameRandomMovieTwice:NO]; 785 | } 786 | 787 | return NO; 788 | } 789 | 790 | AVPlayerItem * tAVPlayerItem=[[AVPlayerItem alloc] initWithAsset:tAsset]; 791 | 792 | if (tAVPlayerItem==nil) 793 | { 794 | __arrayIndex++; 795 | 796 | return [self playNextAsset:nil canPlaySameRandomMovieTwice:NO]; 797 | } 798 | 799 | AVPlayer * tAVPlayer=[[AVPlayer alloc] initWithPlayerItem:tAVPlayerItem]; 800 | 801 | [tAVPlayerItem release]; 802 | 803 | 804 | [_AVPlayerLayer removeFromSuperlayer]; 805 | _AVPlayerLayer=nil; 806 | 807 | _AVPlayerLayer=[AVPlayerLayer playerLayerWithPlayer:tAVPlayer]; 808 | 809 | [tAVPlayer release]; 810 | 811 | if (_AVPlayerLayer==nil) 812 | { 813 | // Display an error message instead of the movie 814 | 815 | // A COMPLETER 816 | 817 | return NO; 818 | } 819 | 820 | CGRect tBackgroundFrame=_backgroundLayer.bounds; 821 | CGRect tFrame=tBackgroundFrame; 822 | 823 | if (_scaling==SHMovieScaleNone) 824 | { 825 | CGSize tAssetSize=tAsset.naturalSize; 826 | 827 | CGFloat tRatio=tAssetSize.width/tBackgroundFrame.size.width; 828 | CGFloat tYRatio=tAssetSize.height/tBackgroundFrame.size.height; 829 | 830 | if (tYRatio>tRatio) 831 | { 832 | tRatio=tYRatio; 833 | } 834 | 835 | if (tRatio>=1.0f) 836 | { 837 | tAssetSize.width=round(tAssetSize.width/tRatio); 838 | tAssetSize.height=round(tAssetSize.height/tRatio); 839 | } 840 | 841 | if (_randomPosition==YES && tRatio<1.0) 842 | { 843 | // Make sure we can randomize the position 844 | 845 | NSSize tSize=tAssetSize; 846 | 847 | tFrame.origin=SSRandomPointForSizeWithinRect(tAssetSize,tBackgroundFrame); 848 | tFrame.size=tSize; 849 | } 850 | else 851 | { 852 | if (_drawBorder==YES) 853 | { 854 | if (tAssetSize.width>(tBackgroundFrame.size.width-2*BORDER_SIZE)) 855 | { 856 | tAssetSize.width=tBackgroundFrame.size.width-2*BORDER_SIZE; 857 | } 858 | 859 | if (tAssetSize.height>(tBackgroundFrame.size.height-2*BORDER_SIZE)) 860 | { 861 | tAssetSize.height=tBackgroundFrame.size.height-2*BORDER_SIZE; 862 | } 863 | } 864 | 865 | tFrame.size=tAssetSize; 866 | 867 | tFrame.origin.x=round(tBackgroundFrame.origin.x+(tBackgroundFrame.size.width-tAssetSize.width)*0.5); 868 | tFrame.origin.y=round(tBackgroundFrame.origin.y+(tBackgroundFrame.size.height-tAssetSize.height)*0.5); 869 | } 870 | } 871 | else 872 | { 873 | if (_scaling==SHMovieScaleAxesIndependently) 874 | _AVPlayerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill; 875 | else 876 | _AVPlayerLayer.videoGravity=AVLayerVideoGravityResizeAspect; 877 | 878 | if (_drawBorder==YES) 879 | { 880 | tFrame=CGRectInset(tBackgroundFrame, BORDER_SIZE, BORDER_SIZE); 881 | } 882 | } 883 | 884 | _AVPlayerLayer.frame=tFrame; 885 | 886 | [_backgroundLayer insertSublayer:_AVPlayerLayer atIndex:0]; 887 | 888 | #ifdef __DEBUG_LOG__ 889 | NSLog(@"Add PlayerLayer"); 890 | #endif 891 | // Set Volume 892 | 893 | switch(_volumeMode) 894 | { 895 | case SHMovieAudioVolumeMute: 896 | 897 | _AVPlayerLayer.player.volume=0.0; 898 | 899 | break; 900 | 901 | case SHMovieAudioVolumeNormal: 902 | 903 | if (_volumeLevelHasBeenModified==NO) 904 | { 905 | if ([tAsset statusOfValueForKey:@"preferredVolume" error:NULL]==AVKeyValueStatusLoaded) 906 | { 907 | _volumeLevel=tAsset.preferredVolume; 908 | } 909 | else 910 | { 911 | _volumeLevel=1.0f; 912 | } 913 | } 914 | 915 | default: 916 | 917 | if (_audioMainScreen==NO || _mainScreen==YES) 918 | { 919 | _AVPlayerLayer.player.volume=(_liveMuted==YES) ? 0.0f :_volumeLevel; 920 | } 921 | else 922 | { 923 | _AVPlayerLayer.player.volume=0; 924 | } 925 | 926 | break; 927 | } 928 | 929 | NSValue * tValue=[preferredNextAssetDictionary objectForKey:SHAssetTimeKey]; 930 | 931 | if (tValue!=nil) 932 | { 933 | CMTime tSeekTime=[tValue CMTimeValue]; 934 | 935 | [_AVPlayerLayer.player seekToTime:tSeekTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; 936 | } 937 | 938 | // Update assets playing list 939 | 940 | [[SHPlayingAssetsRegister sharedRegister] addAsset:tAsset.URL]; 941 | 942 | [_AVPlayerLayer.player play]; 943 | 944 | if (_preview==NO && _showMetadata==YES) 945 | { 946 | CATextLayer * tTitleLayer; 947 | CATextLayer * tCopyrightLayer; 948 | 949 | if (_metadataLayer==nil) 950 | { 951 | CGColorRef tTranslucidBlackColor=CGColorCreateGenericGray(0.0,0.5); 952 | CGRect tRect=_backgroundLayer.bounds; 953 | 954 | tRect.size.height=70; 955 | 956 | // Dark Background 957 | 958 | _metadataLayer=[CALayer layer]; 959 | 960 | _metadataLayer.frame=tRect; 961 | _metadataLayer.backgroundColor=tTranslucidBlackColor; 962 | 963 | CFRelease(tTranslucidBlackColor); 964 | 965 | [_backgroundLayer insertSublayer:_metadataLayer 966 | above:_AVPlayerLayer]; 967 | 968 | _metadataLayer.opacity=0.0f; 969 | 970 | tTitleLayer=[CATextLayer layer]; 971 | 972 | tTitleLayer.font=@"Lucida Grande Bold"; 973 | tTitleLayer.fontSize=35; 974 | tTitleLayer.foregroundColor=CGColorGetConstantColor(kCGColorWhite); 975 | tTitleLayer.frame=CGRectMake(12, 25, tRect.size.width-12,40); 976 | 977 | [_metadataLayer addSublayer:tTitleLayer]; 978 | 979 | tCopyrightLayer=[CATextLayer layer]; 980 | 981 | tCopyrightLayer.font=@"Lucida Grande"; 982 | tCopyrightLayer.fontSize=15; 983 | tCopyrightLayer.foregroundColor=CGColorGetConstantColor(kCGColorWhite); 984 | 985 | tCopyrightLayer.frame=CGRectMake(12, 2, tRect.size.width-12,18); 986 | 987 | [_metadataLayer addSublayer:tCopyrightLayer]; 988 | } 989 | else 990 | { 991 | tTitleLayer=(CATextLayer *)[_metadataLayer sublayers][0]; 992 | tCopyrightLayer=(CATextLayer *)[_metadataLayer sublayers][1]; 993 | } 994 | 995 | if (_metadadataMode==kMovieFrameShowMetadataPeriodically) 996 | { 997 | _timer=[[NSTimer scheduledTimerWithTimeInterval:_metadadataPeriod target:self selector:@selector(showMetadata:) userInfo:nil repeats:YES] retain]; 998 | } 999 | 1000 | [tAVPlayerItem.asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"availableMetadataFormats"] completionHandler:^(){ 1001 | 1002 | if ([tAVPlayerItem.asset statusOfValueForKey:@"availableMetadataFormats" error:NULL]==AVKeyValueStatusLoaded) 1003 | { 1004 | NSArray * tAvailableMetadataFormats=[tAVPlayerItem.asset availableMetadataFormats]; 1005 | 1006 | if ([tAvailableMetadataFormats containsObject:AVMetadataFormatQuickTimeUserData]==YES) 1007 | { 1008 | NSArray * tMetadata=[tAVPlayerItem.asset metadataForFormat:AVMetadataFormatQuickTimeUserData]; 1009 | NSArray * tMetadataItemsArray; 1010 | 1011 | // Title 1012 | 1013 | if (_currentAssetMetadataTitle==nil) 1014 | { 1015 | tMetadataItemsArray=[AVMetadataItem metadataItemsFromArray:tMetadata 1016 | withKey:AVMetadataCommonKeyTitle 1017 | keySpace:AVMetadataKeySpaceCommon]; 1018 | 1019 | if ([tMetadataItemsArray count]>0) 1020 | { 1021 | _currentAssetMetadataTitle=[[NSString alloc] initWithString:[tMetadataItemsArray[0] stringValue]]; 1022 | } 1023 | } 1024 | 1025 | // Copyrights 1026 | 1027 | if (_currentAssetMetadataCopyrights==nil) 1028 | { 1029 | tMetadataItemsArray=[AVMetadataItem metadataItemsFromArray:tMetadata 1030 | withKey:AVMetadataCommonKeyCopyrights 1031 | keySpace:AVMetadataKeySpaceCommon]; 1032 | 1033 | if ([tMetadataItemsArray count]>0) 1034 | { 1035 | _currentAssetMetadataCopyrights=[[NSString alloc] initWithString:[tMetadataItemsArray[0] stringValue]]; 1036 | } 1037 | } 1038 | 1039 | if (_currentAssetMetadataTitle!=nil || _currentAssetMetadataCopyrights!=nil) 1040 | { 1041 | tTitleLayer.string=_currentAssetMetadataTitle; 1042 | tCopyrightLayer.string=_currentAssetMetadataCopyrights; 1043 | 1044 | if (_metadadataMode==kMovieFrameShowMetadataAtStart) 1045 | { 1046 | [self performSelectorOnMainThread:@selector(showMetadata:) 1047 | withObject:nil 1048 | waitUntilDone:NO]; 1049 | } 1050 | } 1051 | } 1052 | } 1053 | }]; 1054 | } 1055 | 1056 | return YES; 1057 | } 1058 | 1059 | - (void)showMetadata:(NSTimer *)inTimer 1060 | { 1061 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideMetadata:) object:nil]; 1062 | 1063 | if (_currentAssetMetadataTitle!=nil || _currentAssetMetadataCopyrights!=nil) 1064 | [_metadataLayer setOpacity:1.0]; 1065 | 1066 | [self performSelector:@selector(hideMetadata:) withObject:nil afterDelay:METADATA_DISPLAY_DURATION]; 1067 | } 1068 | 1069 | - (void)hideMetadata:(id)object 1070 | { 1071 | [_metadataLayer setOpacity:0.0]; 1072 | } 1073 | 1074 | #pragma mark - Configuration 1075 | 1076 | - (BOOL)hasConfigureSheet 1077 | { 1078 | return ([SHSettings isConfigurationLocked]==NO); 1079 | } 1080 | 1081 | - (NSWindow*)configureSheet 1082 | { 1083 | if (_configurationWindowController==nil) 1084 | _configurationWindowController=[[SHConfigurationWindowController alloc] init]; 1085 | 1086 | NSWindow * tWindow=_configurationWindowController.window; 1087 | 1088 | [_configurationWindowController refreshSettings]; 1089 | 1090 | return tWindow; 1091 | } 1092 | 1093 | #pragma mark - Player Item Observer 1094 | 1095 | - (void)playerItemDidPlayToEndMainThread:(AVPlayerItem *)inPlayerItem 1096 | { 1097 | if (inPlayerItem==_AVPlayerLayer.player.currentItem) 1098 | { 1099 | // Update assets playing list 1100 | 1101 | [[SHPlayingAssetsRegister sharedRegister] removeAsset:((AVURLAsset *)inPlayerItem.asset).URL]; 1102 | 1103 | AVPlayer * tCurrentPlayer=[_AVPlayerLayer player]; 1104 | 1105 | if (_timer!=nil) 1106 | { 1107 | [_timer invalidate]; 1108 | 1109 | [_timer release]; 1110 | _timer=nil; 1111 | } 1112 | 1113 | #ifdef __DEBUG_LOG__ 1114 | NSLog(@"Finished playing asset #%lu",__arrayIndex); 1115 | #endif 1116 | 1117 | // Rewind (only one asset and no random position) or play next 1118 | 1119 | if ([__assetsArray count]==1) 1120 | { 1121 | if (_randomPosition==NO) 1122 | { 1123 | [tCurrentPlayer seekToTime:kCMTimeZero]; 1124 | [tCurrentPlayer play]; 1125 | 1126 | if (_preview==NO && _showMetadata==YES) 1127 | { 1128 | if (_metadadataMode==kMovieFrameShowMetadataPeriodically) 1129 | { 1130 | _timer=[[NSTimer scheduledTimerWithTimeInterval:_metadadataPeriod target:self selector:@selector(showMetadata:) userInfo:nil repeats:YES] retain]; 1131 | } 1132 | else 1133 | { 1134 | [self showMetadata:nil]; 1135 | } 1136 | } 1137 | 1138 | return; 1139 | } 1140 | } 1141 | 1142 | [self hideMetadata:nil]; 1143 | 1144 | [_currentAssetMetadataTitle release]; 1145 | _currentAssetMetadataTitle=nil; 1146 | 1147 | [_currentAssetMetadataCopyrights release]; 1148 | _currentAssetMetadataCopyrights=nil; 1149 | 1150 | __arrayIndex++; 1151 | 1152 | if ([self playNextAsset:nil canPlaySameRandomMovieTwice:NO]==NO) 1153 | { 1154 | // A COMPLETER 1155 | } 1156 | } 1157 | } 1158 | 1159 | - (void)playerItemDidPlayToEnd:(NSNotification *)inNotification 1160 | { 1161 | AVPlayerItem * tPlayerItem=(AVPlayerItem *)[inNotification object]; 1162 | 1163 | [self performSelector:@selector(playerItemDidPlayToEndMainThread:) 1164 | onThread:[NSThread mainThread] 1165 | withObject:tPlayerItem 1166 | waitUntilDone:YES]; 1167 | } 1168 | 1169 | #pragma mark - Notifications 1170 | 1171 | - (void)increaseVolume:(NSNotificationCenter *)inNotification 1172 | { 1173 | if ((_audioMainScreen==NO || _mainScreen==YES) && 1174 | (_liveMuted==NO)) 1175 | { 1176 | AVPlayer * tCurrentPlayer=_AVPlayerLayer.player; 1177 | 1178 | _volumeLevel+=0.1f; 1179 | 1180 | if (_volumeLevel>1.0f) 1181 | _volumeLevel=1.0f; 1182 | 1183 | if (tCurrentPlayer!=nil) 1184 | { 1185 | tCurrentPlayer.volume=_volumeLevel; 1186 | 1187 | _volumeLevelHasBeenModified=YES; 1188 | } 1189 | } 1190 | } 1191 | 1192 | - (void)decreaseVolume:(NSNotificationCenter *)inNotification 1193 | { 1194 | if ((_audioMainScreen==NO || _mainScreen==YES) && 1195 | (_liveMuted==NO)) 1196 | { 1197 | AVPlayer * tCurrentPlayer=_AVPlayerLayer.player; 1198 | 1199 | _volumeLevel-=0.1f; 1200 | 1201 | if (_volumeLevel<0.0f) 1202 | _volumeLevel=0.0f; 1203 | 1204 | if (tCurrentPlayer!=nil) 1205 | { 1206 | tCurrentPlayer.volume=_volumeLevel; 1207 | 1208 | _volumeLevelHasBeenModified=YES; 1209 | } 1210 | } 1211 | } 1212 | 1213 | - (void)switchMutedState:(NSNotification *)inNotification 1214 | { 1215 | if (_audioMainScreen==NO || _mainScreen==YES) 1216 | { 1217 | AVPlayer * tCurrentPlayer=_AVPlayerLayer.player; 1218 | 1219 | _liveMuted=!_liveMuted; 1220 | 1221 | if (tCurrentPlayer!=nil) 1222 | { 1223 | tCurrentPlayer.volume=(_liveMuted==YES) ? 0.0f : _volumeLevel; 1224 | 1225 | _volumeLevelHasBeenModified=YES; 1226 | } 1227 | } 1228 | } 1229 | 1230 | @end 1231 | -------------------------------------------------------------------------------- /SaveHollywood/en.lproj/Localized.strings: -------------------------------------------------------------------------------- 1 | "%ld seconds" = "%ld seconds"; 2 | 3 | "Add video or folder" = "Add video or folder"; 4 | 5 | "Add" = "Add"; 6 | 7 | "Version %@ (%@)" = "Version %@ (%@)"; 8 | 9 | "Legal terms" = "Copyright © 2001-%ld Stéphane Sudre\nAll rights reserved."; 10 | 11 | "No videos" = "No videos"; 12 | -------------------------------------------------------------------------------- /SaveHollywood/fr.lproj/Localized.strings: -------------------------------------------------------------------------------- 1 | "%ld seconds" = "%ld secondes"; 2 | 3 | "Add video or folder" = "Ajouter une vidéo ou un dossier"; 4 | 5 | "Add" = "Ajouter"; 6 | 7 | "Version %@ (%@)" = "Version %@ (%@)"; 8 | 9 | "Legal terms" = "Copyright © 2001-%ld Stéphane Sudre\nTous droits réservés."; 10 | 11 | "No videos" = "Aucune vidéo"; 12 | -------------------------------------------------------------------------------- /SaveHollywood/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/packagesdev/savehollywood/435570bd65e70f4a7b3b8c570b989174b62b8755/SaveHollywood/thumbnail.png -------------------------------------------------------------------------------- /SaveHollywood/thumbnail@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/packagesdev/savehollywood/435570bd65e70f4a7b3b8c570b989174b62b8755/SaveHollywood/thumbnail@2x.png --------------------------------------------------------------------------------