├── Bridging-Header.h ├── Constants.swift ├── Credits.html ├── FileHashMethod.swift ├── Languages.swift ├── MainWindowController.swift ├── MainWindowController.xib ├── OpenSubsAccess.swift ├── Podfile ├── Pods ├── GZIP │ └── GZIP │ │ ├── GZIP.h │ │ └── GZIP.m ├── NSData+Base64 │ ├── NSData+Base64.h │ └── NSData+Base64.m ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── spilja.xcuserdatad │ │ └── xcschemes │ │ ├── GZIP.xcscheme │ │ ├── NSData+Base64.xcscheme │ │ ├── Pods-Subtitlr.xcscheme │ │ ├── xcschememanagement.plist │ │ └── xmlrpc.xcscheme ├── Target Support Files │ └── Pods-Subtitlr │ │ ├── Pods-Subtitlr.debug.xcconfig │ │ └── Pods-Subtitlr.release.xcconfig └── xmlrpc │ ├── NSStringAdditions.h │ ├── NSStringAdditions.m │ ├── XMLRPC.h │ ├── XMLRPCConnection.h │ ├── XMLRPCConnection.m │ ├── XMLRPCConnectionDelegate.h │ ├── XMLRPCConnectionManager.h │ ├── XMLRPCConnectionManager.m │ ├── XMLRPCDefaultEncoder.h │ ├── XMLRPCDefaultEncoder.m │ ├── XMLRPCEncoder.h │ ├── XMLRPCEventBasedParser.h │ ├── XMLRPCEventBasedParser.m │ ├── XMLRPCEventBasedParserDelegate.h │ ├── XMLRPCEventBasedParserDelegate.m │ ├── XMLRPCRequest.h │ ├── XMLRPCRequest.m │ ├── XMLRPCResponse.h │ └── XMLRPCResponse.m ├── PopoverController.swift ├── PopoverController.xib ├── README.md ├── Subtitle.swift ├── Subtitlr 2.0 ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── logo.png │ │ ├── logo_128.png │ │ ├── logo_16.png │ │ ├── logo_256-1.png │ │ ├── logo_256.png │ │ ├── logo_32-1.png │ │ ├── logo_32.png │ │ ├── logo_512-1.png │ │ ├── logo_512.png │ │ └── logo_64.png ├── Info.plist └── MainMenu.xib ├── Subtitlr 2.0Tests ├── Info.plist ├── OpenSubsAccessTests.swift └── SubtitlrTests.swift ├── Subtitlr 2.0UITests ├── Info.plist └── UITests.swift ├── Subtitlr.entitlements ├── Subtitlr.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── spilja.xcuserdatad │ └── xcschemes │ ├── Subtitlr 2.0.xcscheme │ └── xcschememanagement.plist ├── Video.swift ├── dropzone_img.png ├── dropzone_img@2x.png ├── opensubs-logo.gif └── opensubs-logo.png /Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Bridging-Header.h 3 | // subs 4 | // 5 | // Created by Lucija Frković on 22/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | #ifndef Bridging_Header_h 10 | #define Bridging_Header_h 11 | 12 | 13 | #import "XMLRPC/XMLRPCConnection.h" 14 | #import "XMLRPC/XMLRPCConnectionDelegate.h" 15 | #import "XMLRPC/XMLRPCConnectionManager.h" 16 | #import "XMLRPC/XMLRPCResponse.h" 17 | #import "XMLRPC/XMLRPCRequest.h" 18 | #import "GZIP/GZIP.h" 19 | 20 | #endif /* Bridging_Header_h */ 21 | 22 | -------------------------------------------------------------------------------- /Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 29/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Constants { 12 | 13 | static let defaultSubtitleLanguage = "eng" 14 | static let OSUserAgent = "eagerMoose" 15 | static let OSconnectionString = "https://api.opensubtitles.org:443/xml-rpc" 16 | 17 | struct OSMethods { 18 | static let logIn = "LogIn" 19 | static let searchSubtitles = "SearchSubtitles" 20 | static let downloadSubtitles = "DownloadSubtitles" 21 | } 22 | 23 | struct Keys { 24 | static let subtitleLanguage = "subtitleLanguage" 25 | } 26 | 27 | static let fileTypes = ["3g2", "3gp", "3gp2", "3gpp", "60d", "ajp", "asf", "asx", "avchd", "avi", "bik", "bix", "box", "cam", "dat", "divx", "dmf", "dv", "dvr-ms", "evo", "flc", "fli", "flic", "flv", "flx", "gvi", "gvp", "h264", "m1v", "m2p", "m2ts", "m2v", "m4e", "m4v", "mjp", "mjpeg", "mjpg", "mkv", "moov", "mov", "movhd", "movie", "movx", "mp4", "mpe", "mpeg", "mpg", "mpv", "mpv2", "mxf", "nsv", "nut", "ogg", "ogm", "omf", "ps", "qt", "ram", "rm", "rmvb", "swf", "ts", "vfw", "vid", "video", "viv", "vivo", "vob", "vro", "wm", "wmv", "wmx", "wrap", "wvx", "wx", "x264", "xvid"] 28 | 29 | 30 | static func getLanguages() -> NSDictionary { 31 | var languages = [String: String]() 32 | 33 | // languages["afr"] = "Afrikaans" 34 | // languages["alb"] = "Albanian" 35 | // languages["ara"] = "Arabic" 36 | // languages["arm"] = "Armenian" 37 | // languages["baq"] = "Basque" 38 | // languages["bel"] = "Belarusian" 39 | // languages["ben"] = "Bengali" 40 | // languages["bos"] = "Bosnian" 41 | // languages["bre"] = "Breton" 42 | // languages["bul"] = "Bulgarian" 43 | // languages["bur"] = "Burmese" 44 | // languages["cat"] = "Catalan" 45 | // languages["chi"] = "Chinese (simplified)" 46 | // languages["zht"] = "Chinese (traditional)" 47 | // languages["zhe"] = "Chinese bilingual" 48 | // languages["hrv"] = "Croatian" 49 | // languages["cze"] = "Czech" 50 | // languages["dan"] = "Danish" 51 | // languages["dut"] = "Dutch" 52 | // languages["eng"] = "English" 53 | // languages["epo"] = "Esperanto" 54 | // languages["est"] = "Estonian" 55 | // languages["fin"] = "Finnish" 56 | // languages["fre"] = "French" 57 | // languages["glg"] = "Galician" 58 | // languages["geo"] = "Georgian" 59 | // languages["ger"] = "German" 60 | // languages["ell"] = "Greek" 61 | // languages["heb"] = "Hebrew" 62 | // languages["hin"] = "Hindi" 63 | // languages["hun"] = "Hungarian" 64 | // languages["ice"] = "Icelandic" 65 | // languages["ind"] = "Indonesian" 66 | // languages["ita"] = "Italian" 67 | // languages["jpn"] = "Japanese" 68 | // languages["kaz"] = "Kazakh" 69 | // languages["khm"] = "Khmer" 70 | // languages["kor"] = "Korean" 71 | // languages["lav"] = "Latvian" 72 | // languages["lit"] = "Lithuanian" 73 | // languages["ltz"] = "Luxembourgish" 74 | // languages["mac"] = "Macedonian" 75 | // languages["may"] = "Malay" 76 | // languages["mal"] = "Malayalam" 77 | // languages["mni"] = "Manipuri" 78 | // languages["mon"] = "Mongolian" 79 | // languages["mne"] = "Montenegrin" 80 | // languages["nor"] = "Norwegian" 81 | // languages["oci"] = "Occitan" 82 | // languages["per"] = "Persian" 83 | // languages["pol"] = "Polish" 84 | // languages["por"] = "Portuguese" 85 | // languages["pob"] = "Portuguese (BR)" 86 | // languages["rum"] = "Romanian" 87 | // languages["rus"] = "Russian" 88 | // languages["scc"] = "Serbian" 89 | // languages["sin"] = "Sinhalese" 90 | // languages["slo"] = "Slovak" 91 | // languages["slv"] = "Slovenian" 92 | // languages["spa"] = "Spanish" 93 | // languages["swa"] = "Swahili" 94 | // languages["swe"] = "Swedish" 95 | // languages["syr"] = "Syriac" 96 | // languages["tgl"] = "Tagalog" 97 | // languages["tam"] = "Tamil" 98 | // languages["tel"] = "Telugu" 99 | // languages["tha"] = "Thai" 100 | // languages["tur"] = "Turkish" 101 | // languages["ukr"] = "Ukrainian" 102 | // languages["urd"] = "Urdu" 103 | // languages["vie"] = "Vietnamese" 104 | 105 | languages["Afrikaans"] = "afr" 106 | languages["Albanian"] = "alb" 107 | languages["Arabic"] = "ara" 108 | languages["Armenian"] = "arm" 109 | languages["Basque"] = "baq" 110 | languages["Belarusian"] = "bel" 111 | languages["Bengali"] = "ben" 112 | languages["Bosnian"] = "bos" 113 | languages["Breton"] = "bre" 114 | languages["Bulgarian"] = "bul" 115 | languages["Burmese"] = "bur" 116 | languages["Catalan"] = "cat" 117 | languages["Chinese (simplified)"] = "chi" 118 | languages["Chinese (traditional)"] = "zht" 119 | languages["Chinese bilingual"] = "zhe" 120 | languages["Croatian"] = "hrv" 121 | languages["Czech"] = "cze" 122 | languages["Danish"] = "dan" 123 | languages["Dutch"] = "dut" 124 | languages["English"] = "eng" 125 | languages["Esperanto"] = "epo" 126 | languages["Estonian"] = "est" 127 | languages["Finnish"] = "fin" 128 | languages["French"] = "fre" 129 | languages["Galician"] = "glg" 130 | languages["Georgian"] = "geo" 131 | languages["German"] = "ger" 132 | languages["Greek"] = "ell" 133 | languages["Hebrew"] = "heb" 134 | languages["Hindi"] = "hin" 135 | languages["Hungarian"] = "hun" 136 | languages["Icelandic"] = "ice" 137 | languages["Indonesian"] = "ind" 138 | languages["Italian"] = "ita" 139 | languages["Japanese"] = "jpn" 140 | languages["Kazakh"] = "kaz" 141 | languages["Khmer"] = "khm" 142 | languages["Korean"] = "kor" 143 | languages["Latvian"] = "lav" 144 | languages["Lithuanian"] = "lit" 145 | languages["Luxembourgish"] = "ltz" 146 | languages["Macedonian"] = "mac" 147 | languages["Malay"] = "may" 148 | languages["Malayalam"] = "mal" 149 | languages["Manipuri"] = "mni" 150 | languages["Mongolian"] = "mon" 151 | languages["Montenegrin"] = "mne" 152 | languages["Norwegian"] = "nor" 153 | languages["Occitan"] = "oci" 154 | languages["Persian"] = "per" 155 | languages["Polish"] = "pol" 156 | languages["Portuguese"] = "por" 157 | languages["Portuguese (BR)"] = "pob" 158 | languages["Romanian"] = "rum" 159 | languages["Russian"] = "rus" 160 | languages["Serbian"] = "scc" 161 | languages["Sinhalese"] = "sin" 162 | languages["Slovak"] = "slo" 163 | languages["Slovenian"] = "slv" 164 | languages["Spanish"] = "spa" 165 | languages["Swahili"] = "swa" 166 | languages["Swedish"] = "swe" 167 | languages["Syriac"] = "syr" 168 | languages["Tagalog"] = "tgl" 169 | languages["Tamil"] = "tam" 170 | languages["Telugu"] = "tel" 171 | languages["Thai"] = "tha" 172 | languages["Turkish"] = "tur" 173 | languages["Ukrainian"] = "ukr" 174 | languages["Urdu"] = "urd" 175 | languages["Vietnamese"] = "vie" 176 | 177 | return languages 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /Credits.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 | 20 |
21 |

Nikac Nikac, mali bik!

22 |

23 |

Subtitle service provided by OpenSubtitles.org

24 | 25 |

OSX App Sandboxing & "Related Items" tutorial Copyright (c) 2015 Stefano Vettor

26 | 27 | 28 |

Cocoa XML-RPC Framework (MIT license - see below) Copyright (c) 2012 Eric Czarny

29 | 30 |

GZIP (zlib license - see below) Copyright (C) 2012 Charcoal Design

31 | 32 |

CocoaPods 33 | (MIT license - see below) 34 | Copyright (c) 2011 - 2015 Eloy Durán , 35 | Fabio Pelosin , 36 | Samuel Giddins , 37 | Marius Rackwitz , 38 | Kyle Fuller , 39 | Boris Bügling , 40 | Orta Therox , and 41 | Olivier Halligon . 42 |

43 | 44 |

45 |

MIT License
46 | 
47 |     
48 | Permission  is hereby granted, free of charge, to any person obtaining a copy of
49 | this  software  and  associated documentation files (the "Software"), to deal in
50 | the  Software  without  restriction,  including without limitation the rights to
51 | use,  copy,  modify,  merge, publish, distribute, sublicense, and/or sell copies
52 | of  the  Software, and to permit persons to whom the Software is furnished to do
53 | so, subject to the following conditions:
54 |     
55 | The  above  copyright notice and this permission notice shall be included in all
56 | copies or substantial portions of the Software.
57 |     
58 | THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 | IMPLIED,  INCLUDING  BUT  NOT  LIMITED  TO  THE  WARRANTIES  OF MERCHANTABILITY,
60 | FITNESS  FOR  A  PARTICULAR  PURPOSE  AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61 | AUTHORS  OR  COPYRIGHT  HOLDERS  BE  LIABLE  FOR  ANY  CLAIM,  DAMAGES  OR OTHER
62 | LIABILITY,  WHETHER  IN  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63 | OUT  OF  OR  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
64 | SOFTWARE.
65 |

66 | 67 |

68 |

BSD License
69 | 
70 | This software is provided 'as-is', without any express or implied
71 | warranty.  In no event will the authors be held liable for any damages
72 | arising from the use of this software.
73 | 
74 | Permission is granted to anyone to use this software for any purpose,
75 | including commercial applications, and to alter it and redistribute it
76 | freely, subject to the following restrictions:
77 | 
78 | 1. The origin of this software must not be misrepresented; you must not
79 | claim that you wrote the original software. If you use this software
80 | in a product, an acknowledgment in the product documentation would be
81 | appreciated but is not required.
82 | 
83 | 2. Altered source versions must be plainly marked as such, and must not be
84 | misrepresented as being the original software.
85 | 
86 | 3. This notice may not be removed or altered from any source distribution.
87 |

88 |
89 | 90 | -------------------------------------------------------------------------------- /FileHashMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileHashMethod.swift 3 | // OpenSubsProj 4 | // 5 | // Created by Lucija Frković on 26/03/15. 6 | // Copyright (c) 2015 Lucija Frković. All rights reserved. 7 | // Based on Objective-C hash implementation for Mac by subsmarine.com 8 | 9 | import Foundation 10 | 11 | class FileHash { 12 | 13 | struct VideoHash { 14 | var fileHash: UInt64; 15 | var fileSize: UInt64; 16 | init() { 17 | fileHash = 0; 18 | fileSize = 0; 19 | } 20 | } 21 | 22 | func stringForHash(hash: UInt64) -> NSString { 23 | return NSString(format: "%qx", hash) 24 | } 25 | 26 | 27 | func hashForPath(path: NSString) -> VideoHash { 28 | var hash = VideoHash(); 29 | 30 | let readFile:NSFileHandle? = NSFileHandle(forReadingAtPath: path as String); 31 | hash = hashForFile(readFile!); 32 | return hash; 33 | } 34 | 35 | func hashForUrl(url: NSURL) -> VideoHash { 36 | var hash = VideoHash(); 37 | let error = NSErrorPointer(); 38 | 39 | var readFile: NSFileHandle? 40 | do { 41 | readFile = try NSFileHandle(forReadingFromURL: url) 42 | } catch let error1 as NSError { 43 | error.memory = error1 44 | readFile = nil 45 | }; 46 | hash = hashForFile(readFile!); 47 | return hash; 48 | } 49 | 50 | func hashForFile(handle: NSFileHandle) -> VideoHash { 51 | var returnHash = VideoHash(); 52 | 53 | let CHUNK_SIZE:UInt64 = 65536; 54 | var fileDataBegin, fileDataEnd:NSData; 55 | var hash:UInt64 = 0; 56 | 57 | fileDataBegin = handle.readDataOfLength(Int(CHUNK_SIZE)); 58 | handle.seekToEndOfFile(); 59 | 60 | let fileSize = handle.offsetInFile; 61 | if (fileSize < CHUNK_SIZE) { 62 | return returnHash; 63 | } 64 | 65 | handle.seekToFileOffset(max(0, (fileSize - CHUNK_SIZE))); 66 | fileDataEnd = handle.readDataOfLength(Int(CHUNK_SIZE)); 67 | 68 | var data_bytes = UnsafeBufferPointer( 69 | start: UnsafePointer(fileDataBegin.bytes), 70 | count: Int(CHUNK_SIZE)/sizeof(UInt64) 71 | ) 72 | 73 | hash = data_bytes.reduce(hash) { $0 &+ $1 } 74 | 75 | data_bytes = UnsafeBufferPointer( 76 | start: UnsafePointer(fileDataEnd.bytes), 77 | count: Int(CHUNK_SIZE)/sizeof(UInt64) 78 | ) 79 | 80 | hash = data_bytes.reduce(hash) { $0 &+ $1 } 81 | 82 | hash = hash &+ fileSize 83 | 84 | returnHash.fileHash = hash; 85 | returnHash.fileSize = fileSize; 86 | 87 | return returnHash; 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Languages.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Languages.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 28/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Language { 12 | 13 | class func getLanguages() -> NSDictionary { 14 | var languages = [String: String]() 15 | 16 | // languages["afr"] = "Afrikaans" 17 | // languages["alb"] = "Albanian" 18 | // languages["ara"] = "Arabic" 19 | // languages["arm"] = "Armenian" 20 | // languages["baq"] = "Basque" 21 | // languages["bel"] = "Belarusian" 22 | // languages["ben"] = "Bengali" 23 | // languages["bos"] = "Bosnian" 24 | // languages["bre"] = "Breton" 25 | // languages["bul"] = "Bulgarian" 26 | // languages["bur"] = "Burmese" 27 | // languages["cat"] = "Catalan" 28 | // languages["chi"] = "Chinese (simplified)" 29 | // languages["zht"] = "Chinese (traditional)" 30 | // languages["zhe"] = "Chinese bilingual" 31 | // languages["hrv"] = "Croatian" 32 | // languages["cze"] = "Czech" 33 | // languages["dan"] = "Danish" 34 | // languages["dut"] = "Dutch" 35 | // languages["eng"] = "English" 36 | // languages["epo"] = "Esperanto" 37 | // languages["est"] = "Estonian" 38 | // languages["fin"] = "Finnish" 39 | // languages["fre"] = "French" 40 | // languages["glg"] = "Galician" 41 | // languages["geo"] = "Georgian" 42 | // languages["ger"] = "German" 43 | // languages["ell"] = "Greek" 44 | // languages["heb"] = "Hebrew" 45 | // languages["hin"] = "Hindi" 46 | // languages["hun"] = "Hungarian" 47 | // languages["ice"] = "Icelandic" 48 | // languages["ind"] = "Indonesian" 49 | // languages["ita"] = "Italian" 50 | // languages["jpn"] = "Japanese" 51 | // languages["kaz"] = "Kazakh" 52 | // languages["khm"] = "Khmer" 53 | // languages["kor"] = "Korean" 54 | // languages["lav"] = "Latvian" 55 | // languages["lit"] = "Lithuanian" 56 | // languages["ltz"] = "Luxembourgish" 57 | // languages["mac"] = "Macedonian" 58 | // languages["may"] = "Malay" 59 | // languages["mal"] = "Malayalam" 60 | // languages["mni"] = "Manipuri" 61 | // languages["mon"] = "Mongolian" 62 | // languages["mne"] = "Montenegrin" 63 | // languages["nor"] = "Norwegian" 64 | // languages["oci"] = "Occitan" 65 | // languages["per"] = "Persian" 66 | // languages["pol"] = "Polish" 67 | // languages["por"] = "Portuguese" 68 | // languages["pob"] = "Portuguese (BR)" 69 | // languages["rum"] = "Romanian" 70 | // languages["rus"] = "Russian" 71 | // languages["scc"] = "Serbian" 72 | // languages["sin"] = "Sinhalese" 73 | // languages["slo"] = "Slovak" 74 | // languages["slv"] = "Slovenian" 75 | // languages["spa"] = "Spanish" 76 | // languages["swa"] = "Swahili" 77 | // languages["swe"] = "Swedish" 78 | // languages["syr"] = "Syriac" 79 | // languages["tgl"] = "Tagalog" 80 | // languages["tam"] = "Tamil" 81 | // languages["tel"] = "Telugu" 82 | // languages["tha"] = "Thai" 83 | // languages["tur"] = "Turkish" 84 | // languages["ukr"] = "Ukrainian" 85 | // languages["urd"] = "Urdu" 86 | // languages["vie"] = "Vietnamese" 87 | 88 | languages["Afrikaans"] = "afr" 89 | languages["Albanian"] = "alb" 90 | languages["Arabic"] = "ara" 91 | languages["Armenian"] = "arm" 92 | languages["Basque"] = "baq" 93 | languages["Belarusian"] = "bel" 94 | languages["Bengali"] = "ben" 95 | languages["Bosnian"] = "bos" 96 | languages["Breton"] = "bre" 97 | languages["Bulgarian"] = "bul" 98 | languages["Burmese"] = "bur" 99 | languages["Catalan"] = "cat" 100 | languages["Chinese (simplified)"] = "chi" 101 | languages["Chinese (traditional)"] = "zht" 102 | languages["Chinese bilingual"] = "zhe" 103 | languages["Croatian"] = "hrv" 104 | languages["Czech"] = "cze" 105 | languages["Danish"] = "dan" 106 | languages["Dutch"] = "dut" 107 | languages["English"] = "eng" 108 | languages["Esperanto"] = "epo" 109 | languages["Estonian"] = "est" 110 | languages["Finnish"] = "fin" 111 | languages["French"] = "fre" 112 | languages["Galician"] = "glg" 113 | languages["Georgian"] = "geo" 114 | languages["German"] = "ger" 115 | languages["Greek"] = "ell" 116 | languages["Hebrew"] = "heb" 117 | languages["Hindi"] = "hin" 118 | languages["Hungarian"] = "hun" 119 | languages["Icelandic"] = "ice" 120 | languages["Indonesian"] = "ind" 121 | languages["Italian"] = "ita" 122 | languages["Japanese"] = "jpn" 123 | languages["Kazakh"] = "kaz" 124 | languages["Khmer"] = "khm" 125 | languages["Korean"] = "kor" 126 | languages["Latvian"] = "lav" 127 | languages["Lithuanian"] = "lit" 128 | languages["Luxembourgish"] = "ltz" 129 | languages["Macedonian"] = "mac" 130 | languages["Malay"] = "may" 131 | languages["Malayalam"] = "mal" 132 | languages["Manipuri"] = "mni" 133 | languages["Mongolian"] = "mon" 134 | languages["Montenegrin"] = "mne" 135 | languages["Norwegian"] = "nor" 136 | languages["Occitan"] = "oci" 137 | languages["Persian"] = "per" 138 | languages["Polish"] = "pol" 139 | languages["Portuguese"] = "por" 140 | languages["Portuguese (BR)"] = "pob" 141 | languages["Romanian"] = "rum" 142 | languages["Russian"] = "rus" 143 | languages["Serbian"] = "scc" 144 | languages["Sinhalese"] = "sin" 145 | languages["Slovak"] = "slo" 146 | languages["Slovenian"] = "slv" 147 | languages["Spanish"] = "spa" 148 | languages["Swahili"] = "swa" 149 | languages["Swedish"] = "swe" 150 | languages["Syriac"] = "syr" 151 | languages["Tagalog"] = "tgl" 152 | languages["Tamil"] = "tam" 153 | languages["Telugu"] = "tel" 154 | languages["Thai"] = "tha" 155 | languages["Turkish"] = "tur" 156 | languages["Ukrainian"] = "ukr" 157 | languages["Urdu"] = "urd" 158 | languages["Vietnamese"] = "vie" 159 | 160 | return languages 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /MainWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowController.swift 3 | // Subtitlr 4 | // 5 | // Created by Lucija Frković on 11/10/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class MainWindowController: NSWindowController, NSTableViewDataSource, NSTableViewDelegate { 12 | 13 | @IBOutlet weak var dropzone: NSView! 14 | @IBOutlet weak var tableView: NSTableView! 15 | @IBOutlet weak var tableContainer: NSView! 16 | @IBOutlet weak var containerView: NSView! 17 | @IBOutlet weak var dropzoneImage: NSImageView! 18 | 19 | let popover = NSPopover() 20 | 21 | var showDropzone = true 22 | 23 | var videos = [Video]() 24 | 25 | override var windowNibName: String { 26 | return "MainWindowController" 27 | } 28 | 29 | override func windowDidLoad() { 30 | super.windowDidLoad() 31 | self.window!.registerForDraggedTypes([NSFilenamesPboardType]) 32 | 33 | //color the container view white, so the dropzone gets white as well 34 | containerView.wantsLayer = true 35 | containerView.layer?.backgroundColor = NSColor.whiteColor().CGColor 36 | 37 | //unregister NSImageView in dropzone view from receiving dragging operation 38 | //otherwise it interferes with dragging files to the whole dropzone area 39 | dropzoneImage.unregisterDraggedTypes() 40 | 41 | tableView.setDelegate(self) 42 | 43 | //bind popover to its controller 44 | popover.contentViewController = PopoverController() 45 | popover.behavior = NSPopoverBehavior.Transient 46 | 47 | } 48 | 49 | 50 | func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation { 51 | return .Copy 52 | } 53 | 54 | func performDragOperation(sender: NSDraggingInfo) -> Bool { 55 | if let board = sender.draggingPasteboard().propertyListForType("NSFilenamesPboardType") as? NSArray { 56 | if let filePaths = board as? [String] { 57 | 58 | //geting the path of dropped file 59 | for path in filePaths { 60 | //only videos are allowed 61 | if Constants.fileTypes.contains((path as NSString).pathExtension.lowercaseString){ 62 | videos.append(Video(path: path)) 63 | } 64 | } 65 | 66 | if videos.count > 0 { 67 | checkAndSwitchToTableView() 68 | 69 | tableView.reloadData() 70 | } 71 | 72 | return true 73 | } 74 | } 75 | return false 76 | } 77 | 78 | //Switches to table view if dropzone is active 79 | func checkAndSwitchToTableView() { 80 | if showDropzone { 81 | showDropzone = false 82 | //remove dropzone and show table with files 83 | containerView.animator().replaceSubview(dropzone, with: tableContainer) 84 | tableContainer!.hidden = false 85 | } 86 | } 87 | 88 | func concludeDragOperation(sender: NSDraggingInfo) { 89 | getSubtitlesForDroppedFiles() 90 | } 91 | 92 | //counters to help with displaying proper notification info 93 | var videoFoundCount = 0 94 | var videoNotFoundCount = 0 95 | var videoNotSearchedCount = 0 96 | 97 | func getSubtitlesForDroppedFiles(){ 98 | for (index, video) in videos.enumerate() { 99 | if video.subStatus == Video.SubtitleStauts.NotSearched { 100 | videoNotSearchedCount += 1 101 | 102 | // Subtitle search and download is done in a separate thread on a lower priority than 103 | // table reload. Otherwise, the application visually gets "stuck" until all subs are downloaded 104 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { 105 | video.downloadSubtitle() 106 | 107 | dispatch_async(dispatch_get_main_queue()){ 108 | if video.subStatus == Video.SubtitleStauts.Found { 109 | self.videoFoundCount += 1 110 | } 111 | else if video.subStatus == Video.SubtitleStauts.NotFound { 112 | self.videoNotFoundCount += 1 113 | } 114 | 115 | //refresh only the first (status) and third(finder icon/link to manual search) columns 116 | //of the table 117 | let columns = NSMutableIndexSet() 118 | columns.addIndex(0) 119 | columns.addIndex(2) 120 | self.tableView.reloadDataForRowIndexes(NSIndexSet(index: index), columnIndexes: columns) 121 | 122 | //if all videos are searched for, display notification 123 | if ((self.videoFoundCount + self.videoNotFoundCount) == self.videoNotSearchedCount){ 124 | self.notifyUser() 125 | self.resetSearchResultCounters() 126 | 127 | } 128 | 129 | } 130 | }) 131 | } 132 | } 133 | 134 | } 135 | 136 | func resetSearchResultCounters(){ 137 | videoNotSearchedCount = 0 138 | videoNotFoundCount = 0 139 | videoFoundCount = 0 140 | } 141 | 142 | func notifyUser(){ 143 | let notify = NSUserNotification() 144 | notify.title = "Finished searching for subtitles" 145 | notify.subtitle = "Subtitles found for \(videoFoundCount) of \(videoNotSearchedCount) videos" 146 | NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notify) 147 | } 148 | 149 | func numberOfRowsInTableView(tableView: NSTableView) -> Int { 150 | return videos.count 151 | } 152 | 153 | //prevents row selection 154 | func tableView(tableView: NSTableView, selectionIndexesForProposedSelection proposedSelectionIndexes: NSIndexSet) -> NSIndexSet { 155 | return NSIndexSet(); 156 | } 157 | 158 | 159 | //Resolve table column values 160 | func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? { 161 | 162 | //middle column showing video path, middle of text is truncated to fit the cell 163 | if tableColumn?.identifier == "fileName" { 164 | var fileName: NSTextField? = tableView.makeViewWithIdentifier("fileName", owner: self) as? NSTextField 165 | 166 | if fileName == nil { 167 | fileName = NSTextField(frame: NSRect()) 168 | fileName!.identifier = "fileName" 169 | fileName?.lineBreakMode = NSLineBreakMode.ByTruncatingMiddle 170 | } 171 | fileName?.stringValue = videos[row].fileName 172 | fileName?.bezeled = false 173 | fileName?.bordered = false 174 | fileName?.selectable = false 175 | fileName?.backgroundColor = NSColor.clearColor() 176 | return fileName 177 | } 178 | else if tableColumn?.identifier == "findSubtitle" { 179 | var findSubtitle: NSButton? = tableView.makeViewWithIdentifier("finder", owner: self) as? NSButton 180 | 181 | if findSubtitle == nil { 182 | findSubtitle = NSButton(frame: NSRect()) 183 | findSubtitle!.identifier = "findSubtitle" 184 | } 185 | 186 | 187 | findSubtitle?.bordered = false 188 | 189 | findSubtitle?.setButtonType(NSButtonType.MomentaryChangeButton) 190 | findSubtitle?.bezelStyle = NSBezelStyle.RoundedDisclosureBezelStyle 191 | findSubtitle?.imagePosition = NSCellImagePosition.ImageOnly 192 | findSubtitle?.target = self 193 | 194 | findSubtitle?.tag = row 195 | 196 | if videos[row].subStatus == Video.SubtitleStauts.Found { 197 | findSubtitle?.image = NSImage(named: NSImageNameRevealFreestandingTemplate) 198 | findSubtitle?.toolTip = "Show subtitle in Finder" 199 | findSubtitle?.action = "revealInFinder:" 200 | 201 | return findSubtitle 202 | } 203 | //show direct search by filename on opensubtitles 204 | else if videos[row].subStatus == Video.SubtitleStauts.NotFound { 205 | 206 | findSubtitle?.image = NSImage(named: NSImageNameShareTemplate) 207 | findSubtitle?.bordered = false 208 | findSubtitle?.toolTip = "Search in browser on OpenSubtitles.org" 209 | findSubtitle?.action = "searchOpenSubs:" 210 | 211 | return findSubtitle 212 | } 213 | 214 | 215 | } 216 | else if tableColumn?.identifier == "status" { 217 | if (videos[row].subStatus == Video.SubtitleStauts.NotSearched) { 218 | var spinner: NSProgressIndicator? = tableView.makeViewWithIdentifier("status", owner: self) as? NSProgressIndicator 219 | 220 | if spinner == nil { 221 | spinner = NSProgressIndicator(frame: NSRect()) 222 | spinner!.identifier = "status" 223 | } 224 | spinner?.style = NSProgressIndicatorStyle.SpinningStyle 225 | spinner?.controlSize = NSControlSize.SmallControlSize 226 | spinner?.startAnimation(nil) 227 | spinner?.bezeled = false 228 | 229 | spinner?.toolTip = "Searching subtitles..." 230 | 231 | return spinner 232 | } 233 | else { 234 | var status: NSTextField? = tableView.makeViewWithIdentifier("status", owner: self) as? NSTextField 235 | 236 | if status == nil { 237 | status = NSTextField(frame: NSRect()) 238 | status!.identifier = "status" 239 | } 240 | status?.stringValue = videos[row].subStatus == Video.SubtitleStauts.Found ? "✓" : "x" 241 | status?.font = videos[row].subStatus == Video.SubtitleStauts.Found ? NSFont(name: "Devanagari MT", size: 12): NSFont(name: "Zapf Dingbats", size: 12) 242 | status?.alignment = NSTextAlignment.Center 243 | status?.bezeled = false 244 | status?.bordered = false 245 | status?.selectable = false 246 | status?.backgroundColor = NSColor.clearColor() 247 | status?.toolTip = videos[row].subStatus == Video.SubtitleStauts.Found ? "Subtitle was found and downloaded to video location.": "Subtitle was not found." 248 | 249 | 250 | return status 251 | } 252 | 253 | } 254 | 255 | return nil 256 | } 257 | 258 | /* Show subtitle in finder. 259 | Finder icon is assigned a tag value corresponding to matching file's array index 260 | */ 261 | func revealInFinder(sender: NSButton){ 262 | let url = NSURL.fileURLWithPath(videos[sender.tag].subtitle!.path) 263 | NSWorkspace.sharedWorkspace().activateFileViewerSelectingURLs([url]) 264 | } 265 | 266 | func searchOpenSubs(sender: NSButton){ 267 | let lang = NSUserDefaults.standardUserDefaults().valueForKey(Constants.Keys.subtitleLanguage) as! String 268 | let urlString = "http://www.opensubtitles.org/en/search2/sublanguageid-\(lang)/moviename-\(videos[sender.tag].fileName)" 269 | let safeUrl = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())! 270 | let url = NSURL(string: safeUrl) 271 | NSWorkspace.sharedWorkspace().openURL(url!) 272 | } 273 | 274 | //opens or closes settings popover 275 | @IBAction func togglePopover(sender: NSButton) { 276 | if popover.shown { 277 | popover.close() 278 | } 279 | else { 280 | popover.showRelativeToRect( sender.bounds, ofView: sender, preferredEdge: NSRectEdge(rawValue: 3)!) 281 | } 282 | } 283 | 284 | @IBAction func selectVideoFilesFromFinder(sender: NSButton) { 285 | sender.enabled = false 286 | 287 | let openPanel = NSOpenPanel() 288 | openPanel.allowsMultipleSelection = true 289 | openPanel.allowedFileTypes = Constants.fileTypes 290 | openPanel.allowsOtherFileTypes = false 291 | openPanel.canChooseFiles = true 292 | openPanel.canChooseDirectories = false 293 | openPanel.canCreateDirectories = false 294 | openPanel.allowsConcurrentViewDrawing = false 295 | 296 | openPanel.beginWithCompletionHandler{result -> Void in 297 | if result == NSFileHandlingPanelOKButton { 298 | for file in openPanel.URLs { 299 | self.videos.append(Video(path: file.path!)) 300 | self.checkAndSwitchToTableView() 301 | } 302 | self.tableView.reloadData() 303 | self.getSubtitlesForDroppedFiles() 304 | } 305 | sender.enabled = true 306 | } 307 | } 308 | 309 | } 310 | -------------------------------------------------------------------------------- /MainWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 44 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | YnBsaXN0MDDUAQIDBAUGJCVYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKkHCBES 240 | EwsKGR9VJG51bGzUCQoLDA0ODxBWJGNsYXNzVHR5cGVXc3VidHlwZV8QEl9fQ0FDb2RpbmdDb250ZW50 241 | c4AIgAOAAoAEWWZyb21SaWdodFZtb3ZlSW7SFAkVGFpOUy5vYmplY3RzohYXgAWABoAH0hobHB1aJGNs 242 | YXNzbmFtZVgkY2xhc3Nlc1dOU0FycmF5ohweWE5TT2JqZWN00hobICFcQ0FUcmFuc2l0aW9uoyIjHlxD 243 | QVRyYW5zaXRpb25bQ0FBbmltYXRpb25fEA9OU0tleWVkQXJjaGl2ZXLRJidUcm9vdIABAAgAEQAaACMA 244 | LQAyADcAQQBHAFAAVwBcAGQAeQB7AH0AfwCBAIsAkgCXAKIApQCnAKkAqwCwALsAxADMAM8A2ADdAOoA 245 | 7gD7AQcBGQEcASEAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAABIw 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /OpenSubsAccess.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSubsAccess.swift 3 | // Subtitlr 4 | // 5 | // Created by Lucija Frković on 19/08/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class OpenSubsAccess { 13 | 14 | var token: String? 15 | 16 | /** 17 | Used to communicate to OpenSubtitles.org 18 | Synchronised requests are made to OpenSubtitles via HTTPS connection, using 19 | XML-RPC protocol (Cocoa XML-RPC framework is used) 20 | 21 | Timeout set to 30sec 22 | */ 23 | func talkToOpenSubs(method: String, params: [AnyObject]) -> NSDictionary? { 24 | 25 | let url = NSURL(string: Constants.OSconnectionString) 26 | let request = XMLRPCRequest(URL: url) 27 | 28 | request.setMethod(method, withParameters: params) 29 | request.setTimeoutInterval(NSTimeInterval(30)) //Timeout set to 30sec 30 | do { 31 | //fuck yeah!!! 32 | let response = try XMLRPCConnection.sendSynchronousXMLRPCRequest(request) 33 | return response.object() as? NSDictionary 34 | 35 | } catch { 36 | //print(error) 37 | //TODO: error handling! 38 | //maybe unnecessary? 39 | } 40 | 41 | return nil 42 | } 43 | 44 | /** 45 | Tries to log in to OpenSubtitles.org, returns 46 | token to be reused in a single session 47 | */ 48 | func logIn() { 49 | let resultDict = talkToOpenSubs(Constants.OSMethods.logIn, params: ["", "", "eng", Constants.OSUserAgent]) 50 | if resultDict != nil && resultDict!.valueForKey("token") != nil { 51 | token = resultDict!.valueForKey("token") as? String 52 | } 53 | 54 | } 55 | 56 | 57 | /** 58 | Creates the appropriate OpenSubtitles structure to get subtitle info for a particular video. 59 | Checks whether a required subtitle exists, returns its ID and format 60 | */ 61 | 62 | func getSubtitle(hash: String, size: Double) -> (id: Int, format: String)? { 63 | if (token != nil) { 64 | var params = [AnyObject]() 65 | params.append(token!) 66 | 67 | var video = [String:AnyObject]() 68 | video["sublanguageid"] = NSUserDefaults.standardUserDefaults().valueForKey(Constants.Keys.subtitleLanguage) as! String 69 | video["moviehash"] = hash 70 | video["moviesize"] = size 71 | var videos = [AnyObject]() 72 | videos.append(video) 73 | 74 | params.append(videos) 75 | 76 | if let resultDict = talkToOpenSubs(Constants.OSMethods.searchSubtitles, params: params) as NSDictionary! { 77 | 78 | if let firstResult = (resultDict["data"] as? NSArray) { 79 | if (firstResult.count > 0){ 80 | let firstSubId = firstResult[0]["IDSubtitleFile"] as! String 81 | let subtitleFormat = firstResult[0]["SubFormat"] as! String 82 | return (Int(firstSubId)!, subtitleFormat) 83 | } 84 | } 85 | 86 | } 87 | 88 | 89 | } 90 | return nil 91 | } 92 | 93 | 94 | 95 | func downloadSub(subId: Int, format: String) -> NSData? { 96 | if token != nil { 97 | var params = [AnyObject]() 98 | params.append(token!) 99 | 100 | var subIds = [Int]() 101 | subIds.append(subId) 102 | params.append(subIds) 103 | 104 | let resultDict = talkToOpenSubs(Constants.OSMethods.downloadSubtitles, params: params) as NSDictionary! 105 | 106 | let subtitle = ((resultDict["data"] as! NSArray)[0] as! NSDictionary)["data"] as! String 107 | let subFile = NSData(base64EncodedString: subtitle, options: [])!.gunzippedData() 108 | 109 | return subFile 110 | } 111 | 112 | return nil 113 | } 114 | } -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :osx, '10.10' 3 | use_frameworks! 4 | 5 | target "Subtitlr" do 6 | pod 'xmlrpc', '~> 2.3.4' 7 | pod 'GZIP', '~> 1.1.1' 8 | target 'SubtitlrTests' do 9 | inherit! :search_paths 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Pods/GZIP/GZIP/GZIP.h: -------------------------------------------------------------------------------- 1 | // 2 | // GZIP.h 3 | // 4 | // Version 1.1.1 5 | // 6 | // Created by Nick Lockwood on 03/06/2012. 7 | // Copyright (C) 2012 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/GZIP 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | 34 | #import 35 | 36 | 37 | @interface NSData (GZIP) 38 | 39 | - (nullable NSData *)gzippedDataWithCompressionLevel:(float)level; 40 | - (nullable NSData *)gzippedData; 41 | - (nullable NSData *)gunzippedData; 42 | - (BOOL)isGzippedData; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Pods/GZIP/GZIP/GZIP.m: -------------------------------------------------------------------------------- 1 | // 2 | // GZIP.m 3 | // 4 | // Version 1.1.1 5 | // 6 | // Created by Nick Lockwood on 03/06/2012. 7 | // Copyright (C) 2012 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/GZIP 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | 34 | #import "GZIP.h" 35 | #import 36 | #import 37 | 38 | 39 | #pragma clang diagnostic ignored "-Wcast-qual" 40 | 41 | 42 | @implementation NSData (GZIP) 43 | 44 | static void *libzOpen() 45 | { 46 | static void *libz; 47 | static dispatch_once_t onceToken; 48 | dispatch_once(&onceToken, ^{ 49 | libz = dlopen("/usr/lib/libz.dylib", RTLD_LAZY); 50 | }); 51 | return libz; 52 | } 53 | 54 | - (NSData *)gzippedDataWithCompressionLevel:(float)level 55 | { 56 | if (self.length == 0 || [self isGzippedData]) 57 | { 58 | return self; 59 | } 60 | 61 | void *libz = libzOpen(); 62 | int (*deflateInit2_)(z_streamp, int, int, int, int, int, const char *, int) = 63 | (int (*)(z_streamp, int, int, int, int, int, const char *, int))dlsym(libz, "deflateInit2_"); 64 | int (*deflate)(z_streamp, int) = (int (*)(z_streamp, int))dlsym(libz, "deflate"); 65 | int (*deflateEnd)(z_streamp) = (int (*)(z_streamp))dlsym(libz, "deflateEnd"); 66 | 67 | z_stream stream; 68 | stream.zalloc = Z_NULL; 69 | stream.zfree = Z_NULL; 70 | stream.opaque = Z_NULL; 71 | stream.avail_in = (uint)self.length; 72 | stream.next_in = (Bytef *)(void *)self.bytes; 73 | stream.total_out = 0; 74 | stream.avail_out = 0; 75 | 76 | static const NSUInteger ChunkSize = 16384; 77 | 78 | NSMutableData *output = nil; 79 | int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9)); 80 | if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) 81 | { 82 | output = [NSMutableData dataWithLength:ChunkSize]; 83 | while (stream.avail_out == 0) 84 | { 85 | if (stream.total_out >= output.length) 86 | { 87 | output.length += ChunkSize; 88 | } 89 | stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; 90 | stream.avail_out = (uInt)(output.length - stream.total_out); 91 | deflate(&stream, Z_FINISH); 92 | } 93 | deflateEnd(&stream); 94 | output.length = stream.total_out; 95 | } 96 | 97 | return output; 98 | } 99 | 100 | - (NSData *)gzippedData 101 | { 102 | return [self gzippedDataWithCompressionLevel:-1.0f]; 103 | } 104 | 105 | - (NSData *)gunzippedData 106 | { 107 | if (self.length == 0 || ![self isGzippedData]) 108 | { 109 | return self; 110 | } 111 | 112 | void *libz = libzOpen(); 113 | int (*inflateInit2_)(z_streamp, int, const char *, int) = 114 | (int (*)(z_streamp, int, const char *, int))dlsym(libz, "inflateInit2_"); 115 | int (*inflate)(z_streamp, int) = (int (*)(z_streamp, int))dlsym(libz, "inflate"); 116 | int (*inflateEnd)(z_streamp) = (int (*)(z_streamp))dlsym(libz, "inflateEnd"); 117 | 118 | z_stream stream; 119 | stream.zalloc = Z_NULL; 120 | stream.zfree = Z_NULL; 121 | stream.avail_in = (uint)self.length; 122 | stream.next_in = (Bytef *)self.bytes; 123 | stream.total_out = 0; 124 | stream.avail_out = 0; 125 | 126 | NSMutableData *output = nil; 127 | if (inflateInit2(&stream, 47) == Z_OK) 128 | { 129 | int status = Z_OK; 130 | output = [NSMutableData dataWithCapacity:self.length * 2]; 131 | while (status == Z_OK) 132 | { 133 | if (stream.total_out >= output.length) 134 | { 135 | output.length += self.length / 2; 136 | } 137 | stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; 138 | stream.avail_out = (uInt)(output.length - stream.total_out); 139 | status = inflate (&stream, Z_SYNC_FLUSH); 140 | } 141 | if (inflateEnd(&stream) == Z_OK) 142 | { 143 | if (status == Z_STREAM_END) 144 | { 145 | output.length = stream.total_out; 146 | } 147 | } 148 | } 149 | 150 | return output; 151 | } 152 | 153 | - (BOOL)isGzippedData 154 | { 155 | const UInt8 *bytes = (const UInt8 *)self.bytes; 156 | return (self.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /Pods/NSData+Base64/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.h 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import 25 | 26 | void *NewBase64Decode( 27 | const char *inputBuffer, 28 | size_t length, 29 | size_t *outputLength); 30 | 31 | char *NewBase64Encode( 32 | const void *inputBuffer, 33 | size_t length, 34 | bool separateLines, 35 | size_t *outputLength); 36 | 37 | @interface NSData (Base64) 38 | 39 | + (NSData *)dataFromBase64String:(NSString *)aString; 40 | - (NSString *)base64EncodedString; 41 | 42 | // added by Hiroshi Hashiguchi 43 | - (NSString *)base64EncodedStringWithSeparateLines:(BOOL)separateLines; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Pods/NSData+Base64/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // base64 4 | // 5 | // Created by Matt Gallagher on 2009/06/03. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import "NSData+Base64.h" 25 | 26 | // 27 | // Mapping from 6 bit pattern to ASCII character. 28 | // 29 | static unsigned char base64EncodeLookup[65] = 30 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 31 | 32 | // 33 | // Definition for "masked-out" areas of the base64DecodeLookup mapping 34 | // 35 | #define xx 65 36 | 37 | // 38 | // Mapping from ASCII character to 6 bit pattern. 39 | // 40 | static unsigned char base64DecodeLookup[256] = 41 | { 42 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 43 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 44 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63, 45 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx, 46 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 47 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx, 48 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 49 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx, 50 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 51 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 52 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 53 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 54 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 55 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 56 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 57 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 58 | }; 59 | 60 | // 61 | // Fundamental sizes of the binary and base64 encode/decode units in bytes 62 | // 63 | #define BINARY_UNIT_SIZE 3 64 | #define BASE64_UNIT_SIZE 4 65 | 66 | // 67 | // NewBase64Decode 68 | // 69 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced 70 | // output buffer. 71 | // 72 | // inputBuffer - the source ASCII string for the decode 73 | // length - the length of the string or -1 (to specify strlen should be used) 74 | // outputLength - if not-NULL, on output will contain the decoded length 75 | // 76 | // returns the decoded buffer. Must be free'd by caller. Length is given by 77 | // outputLength. 78 | // 79 | void *NewBase64Decode( 80 | const char *inputBuffer, 81 | size_t length, 82 | size_t *outputLength) 83 | { 84 | if (length == -1) 85 | { 86 | length = strlen(inputBuffer); 87 | } 88 | 89 | size_t outputBufferSize = 90 | ((length+BASE64_UNIT_SIZE-1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; 91 | unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize); 92 | 93 | size_t i = 0; 94 | size_t j = 0; 95 | while (i < length) 96 | { 97 | // 98 | // Accumulate 4 valid characters (ignore everything else) 99 | // 100 | unsigned char accumulated[BASE64_UNIT_SIZE]; 101 | size_t accumulateIndex = 0; 102 | while (i < length) 103 | { 104 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; 105 | if (decode != xx) 106 | { 107 | accumulated[accumulateIndex] = decode; 108 | accumulateIndex++; 109 | 110 | if (accumulateIndex == BASE64_UNIT_SIZE) 111 | { 112 | break; 113 | } 114 | } 115 | } 116 | 117 | // 118 | // Store the 6 bits from each of the 4 characters as 3 bytes 119 | // 120 | // (Uses improved bounds checking suggested by Alexandre Colucci) 121 | // 122 | if(accumulateIndex >= 2) 123 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); 124 | if(accumulateIndex >= 3) 125 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); 126 | if(accumulateIndex >= 4) 127 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; 128 | j += accumulateIndex - 1; 129 | } 130 | 131 | if (outputLength) 132 | { 133 | *outputLength = j; 134 | } 135 | return outputBuffer; 136 | } 137 | 138 | // 139 | // NewBase64Encode 140 | // 141 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced 142 | // output buffer. 143 | // 144 | // inputBuffer - the source data for the encode 145 | // length - the length of the input in bytes 146 | // separateLines - if zero, no CR/LF characters will be added. Otherwise 147 | // a CR/LF pair will be added every 64 encoded chars. 148 | // outputLength - if not-NULL, on output will contain the encoded length 149 | // (not including terminating 0 char) 150 | // 151 | // returns the encoded buffer. Must be free'd by caller. Length is given by 152 | // outputLength. 153 | // 154 | char *NewBase64Encode( 155 | const void *buffer, 156 | size_t length, 157 | bool separateLines, 158 | size_t *outputLength) 159 | { 160 | const unsigned char *inputBuffer = (const unsigned char *)buffer; 161 | 162 | #define MAX_NUM_PADDING_CHARS 2 163 | #define OUTPUT_LINE_LENGTH 64 164 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) 165 | #define CR_LF_SIZE 2 166 | 167 | // 168 | // Byte accurate calculation of final buffer size 169 | // 170 | size_t outputBufferSize = 171 | ((length / BINARY_UNIT_SIZE) 172 | + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) 173 | * BASE64_UNIT_SIZE; 174 | if (separateLines) 175 | { 176 | outputBufferSize += 177 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; 178 | } 179 | 180 | // 181 | // Include space for a terminating zero 182 | // 183 | outputBufferSize += 1; 184 | 185 | // 186 | // Allocate the output buffer 187 | // 188 | char *outputBuffer = (char *)malloc(outputBufferSize); 189 | if (!outputBuffer) 190 | { 191 | return NULL; 192 | } 193 | 194 | size_t i = 0; 195 | size_t j = 0; 196 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length; 197 | size_t lineEnd = lineLength; 198 | 199 | while (true) 200 | { 201 | if (lineEnd > length) 202 | { 203 | lineEnd = length; 204 | } 205 | 206 | for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) 207 | { 208 | // 209 | // Inner loop: turn 48 bytes into 64 base64 characters 210 | // 211 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 212 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 213 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 214 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) 215 | | ((inputBuffer[i + 2] & 0xC0) >> 6)]; 216 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; 217 | } 218 | 219 | if (lineEnd == length) 220 | { 221 | break; 222 | } 223 | 224 | // 225 | // Add the newline 226 | // 227 | outputBuffer[j++] = '\r'; 228 | outputBuffer[j++] = '\n'; 229 | lineEnd += lineLength; 230 | } 231 | 232 | if (i + 1 < length) 233 | { 234 | // 235 | // Handle the single '=' case 236 | // 237 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 238 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) 239 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; 240 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; 241 | outputBuffer[j++] = '='; 242 | } 243 | else if (i < length) 244 | { 245 | // 246 | // Handle the double '=' case 247 | // 248 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; 249 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; 250 | outputBuffer[j++] = '='; 251 | outputBuffer[j++] = '='; 252 | } 253 | outputBuffer[j] = 0; 254 | 255 | // 256 | // Set the output length and return the buffer 257 | // 258 | if (outputLength) 259 | { 260 | *outputLength = j; 261 | } 262 | return outputBuffer; 263 | } 264 | 265 | @implementation NSData (Base64) 266 | 267 | // 268 | // dataFromBase64String: 269 | // 270 | // Creates an NSData object containing the base64 decoded representation of 271 | // the base64 string 'aString' 272 | // 273 | // Parameters: 274 | // aString - the base64 string to decode 275 | // 276 | // returns the autoreleased NSData representation of the base64 string 277 | // 278 | + (NSData *)dataFromBase64String:(NSString *)aString 279 | { 280 | NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding]; 281 | size_t outputLength; 282 | void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength); 283 | NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength]; 284 | free(outputBuffer); 285 | return result; 286 | } 287 | 288 | // 289 | // base64EncodedString 290 | // 291 | // Creates an NSString object that contains the base 64 encoding of the 292 | // receiver's data. Lines are broken at 64 characters long. 293 | // 294 | // returns an autoreleased NSString being the base 64 representation of the 295 | // receiver. 296 | // 297 | - (NSString *)base64EncodedString 298 | { 299 | size_t outputLength; 300 | char *outputBuffer = 301 | NewBase64Encode([self bytes], [self length], true, &outputLength); 302 | 303 | NSString *result = 304 | [[[NSString alloc] 305 | initWithBytes:outputBuffer 306 | length:outputLength 307 | encoding:NSASCIIStringEncoding] 308 | autorelease]; 309 | free(outputBuffer); 310 | return result; 311 | } 312 | 313 | // added by Hiroshi Hashiguchi 314 | - (NSString *)base64EncodedStringWithSeparateLines:(BOOL)separateLines 315 | { 316 | size_t outputLength; 317 | char *outputBuffer = 318 | NewBase64Encode([self bytes], [self length], separateLines, &outputLength); 319 | 320 | NSString *result = 321 | [[[NSString alloc] 322 | initWithBytes:outputBuffer 323 | length:outputLength 324 | encoding:NSASCIIStringEncoding] 325 | autorelease]; 326 | free(outputBuffer); 327 | return result; 328 | } 329 | 330 | 331 | @end 332 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/GZIP.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/NSData+Base64.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/Pods-Subtitlr.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GZIP.xcscheme 8 | 9 | isShown 10 | 11 | 12 | NSData+Base64.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Pods-Subtitlr.xcscheme 18 | 19 | isShown 20 | 21 | 22 | xmlrpc.xcscheme 23 | 24 | isShown 25 | 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 1F98E46E9E64A5DBA3D6FE096D8FF04A 31 | 32 | primary 33 | 34 | 35 | 701D6F5D626C094A841AE2CEB07673C1 36 | 37 | primary 38 | 39 | 40 | 83DC367090DFF5512A7BBF0CA26C393D 41 | 42 | primary 43 | 44 | 45 | C709A40BDCA702C4FFF9216B0E7653DF 46 | 47 | primary 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/xmlrpc.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Subtitlr/Pods-Subtitlr.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GZIP" "${PODS_ROOT}/Headers/Public/NSData+Base64" "${PODS_ROOT}/Headers/Public/xmlrpc" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GZIP" -isystem "${PODS_ROOT}/Headers/Public/NSData+Base64" -isystem "${PODS_ROOT}/Headers/Public/xmlrpc" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"GZIP" -l"NSData+Base64" -l"xmlrpc" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Subtitlr/Pods-Subtitlr.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GZIP" "${PODS_ROOT}/Headers/Public/NSData+Base64" "${PODS_ROOT}/Headers/Public/xmlrpc" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GZIP" -isystem "${PODS_ROOT}/Headers/Public/NSData+Base64" -isystem "${PODS_ROOT}/Headers/Public/xmlrpc" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"GZIP" -l"NSData+Base64" -l"xmlrpc" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/xmlrpc/NSStringAdditions.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSString (NSStringAdditions) 4 | 5 | + (NSString *)stringByGeneratingUUID; 6 | 7 | #pragma mark - 8 | 9 | - (NSString *)unescapedString; 10 | 11 | - (NSString *)escapedString; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Pods/xmlrpc/NSStringAdditions.m: -------------------------------------------------------------------------------- 1 | #import "NSStringAdditions.h" 2 | 3 | @implementation NSString (NSStringAdditions) 4 | 5 | + (NSString *)stringByGeneratingUUID { 6 | CFUUIDRef UUIDReference = CFUUIDCreate(nil); 7 | CFStringRef temporaryUUIDString = CFUUIDCreateString(nil, UUIDReference); 8 | 9 | CFRelease(UUIDReference); 10 | #if ! __has_feature(objc_arc) 11 | return [NSMakeCollectable(temporaryUUIDString) autorelease]; 12 | #else 13 | return (__bridge_transfer NSString*)temporaryUUIDString; 14 | #endif 15 | } 16 | 17 | #pragma mark - 18 | 19 | - (NSString *)unescapedString { 20 | NSMutableString *string = [NSMutableString stringWithString: self]; 21 | 22 | [string replaceOccurrencesOfString: @"&" withString: @"&" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 23 | [string replaceOccurrencesOfString: @""" withString: @"\"" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 24 | [string replaceOccurrencesOfString: @"'" withString: @"'" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 25 | [string replaceOccurrencesOfString: @"9" withString: @"'" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 26 | [string replaceOccurrencesOfString: @"’" withString: @"'" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 27 | [string replaceOccurrencesOfString: @"–" withString: @"'" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 28 | [string replaceOccurrencesOfString: @">" withString: @">" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 29 | [string replaceOccurrencesOfString: @"<" withString: @"<" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 30 | 31 | return [NSString stringWithString: string]; 32 | } 33 | 34 | - (NSString *)escapedString { 35 | NSMutableString *string = [NSMutableString stringWithString: self]; 36 | 37 | // NOTE: we use unicode entities instead of & > < etc. since some hosts (powweb, fatcow, and similar) 38 | // have a weird PHP/libxml2 combination that ignores regular entities 39 | [string replaceOccurrencesOfString: @"&" withString: @"&" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 40 | [string replaceOccurrencesOfString: @">" withString: @">" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 41 | [string replaceOccurrencesOfString: @"<" withString: @"<" options: NSLiteralSearch range: NSMakeRange(0, [string length])]; 42 | 43 | return [NSString stringWithString: string]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPC.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCConnection.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "XMLRPCConnectionDelegate.h" 3 | 4 | @class XMLRPCConnectionManager, XMLRPCRequest, XMLRPCResponse; 5 | 6 | @interface XMLRPCConnection : NSObject { 7 | XMLRPCConnectionManager *myManager; 8 | XMLRPCRequest *myRequest; 9 | NSString *myIdentifier; 10 | NSMutableData *myData; 11 | NSURLConnection *myConnection; 12 | id myDelegate; 13 | } 14 | 15 | - (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate manager: (XMLRPCConnectionManager *)manager; 16 | 17 | #pragma mark - 18 | 19 | + (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request error: (NSError **)error; 20 | 21 | #pragma mark - 22 | 23 | - (NSString *)identifier; 24 | 25 | #pragma mark - 26 | 27 | - (id)delegate; 28 | 29 | #pragma mark - 30 | 31 | - (void)cancel; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCConnection.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCConnection.h" 2 | #import "XMLRPCConnectionManager.h" 3 | #import "XMLRPCRequest.h" 4 | #import "XMLRPCResponse.h" 5 | #import "NSStringAdditions.h" 6 | 7 | static NSOperationQueue *parsingQueue; 8 | 9 | @interface XMLRPCConnection (XMLRPCConnectionPrivate) 10 | 11 | - (void)connection: (NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 12 | 13 | - (void)connection: (NSURLConnection *)connection didReceiveData: (NSData *)data; 14 | 15 | - (void)connection: (NSURLConnection *)connection didSendBodyData: (NSInteger)bytesWritten totalBytesWritten: (NSInteger)totalBytesWritten totalBytesExpectedToWrite: (NSInteger)totalBytesExpectedToWrite; 16 | 17 | - (void)connection: (NSURLConnection *)connection didFailWithError: (NSError *)error; 18 | 19 | #pragma mark - 20 | 21 | - (BOOL)connection: (NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace; 22 | 23 | - (void)connection: (NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge; 24 | 25 | - (void)connection: (NSURLConnection *)connection didCancelAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge; 26 | 27 | - (void)connectionDidFinishLoading: (NSURLConnection *)connection; 28 | 29 | #pragma mark - 30 | 31 | - (void)timeoutExpired; 32 | - (void)invalidateTimer; 33 | 34 | #pragma mark - 35 | 36 | + (NSOperationQueue *)parsingQueue; 37 | 38 | @end 39 | 40 | #pragma mark - 41 | 42 | @implementation XMLRPCConnection 43 | 44 | - (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate manager: (XMLRPCConnectionManager *)manager { 45 | self = [super init]; 46 | if (self) { 47 | #if ! __has_feature(objc_arc) 48 | myManager = [manager retain]; 49 | myRequest = [request retain]; 50 | myIdentifier = [[NSString stringByGeneratingUUID] retain]; 51 | #else 52 | myManager = manager; 53 | myRequest = request; 54 | myIdentifier = [NSString stringByGeneratingUUID]; 55 | #endif 56 | myData = [[NSMutableData alloc] init]; 57 | 58 | myConnection = [[NSURLConnection alloc] initWithRequest: [request request] delegate: self startImmediately:NO]; 59 | [myConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] 60 | forMode:NSDefaultRunLoopMode]; 61 | [myConnection start]; 62 | 63 | #if ! __has_feature(objc_arc) 64 | myDelegate = [delegate retain]; 65 | #else 66 | myDelegate = delegate; 67 | #endif 68 | 69 | if (myConnection) { 70 | NSLog(@"The connection, %@, has been established!", myIdentifier); 71 | 72 | [self performSelector:@selector(timeoutExpired) withObject:nil afterDelay:[myRequest timeout]]; 73 | } else { 74 | NSLog(@"The connection, %@, could not be established!", myIdentifier); 75 | #if ! __has_feature(objc_arc) 76 | [self release]; 77 | #endif 78 | return nil; 79 | } 80 | } 81 | 82 | return self; 83 | } 84 | 85 | #pragma mark - 86 | 87 | + (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request error: (NSError **)error { 88 | NSHTTPURLResponse *response = nil; 89 | #if ! __has_feature(objc_arc) 90 | NSData *data = [[[NSURLConnection sendSynchronousRequest: [request request] returningResponse: &response error: error] retain] autorelease]; 91 | #else 92 | NSData *data = [NSURLConnection sendSynchronousRequest: [request request] returningResponse: &response error: error]; 93 | #endif 94 | 95 | if (response) { 96 | NSInteger statusCode = [response statusCode]; 97 | 98 | if ((statusCode < 400) && data) { 99 | #if ! __has_feature(objc_arc) 100 | return [[[XMLRPCResponse alloc] initWithData: data] autorelease]; 101 | #else 102 | return [[XMLRPCResponse alloc] initWithData: data]; 103 | #endif 104 | } 105 | } 106 | 107 | return nil; 108 | } 109 | 110 | #pragma mark - 111 | 112 | - (NSString *)identifier { 113 | #if ! __has_feature(objc_arc) 114 | return [[myIdentifier retain] autorelease]; 115 | #else 116 | return myIdentifier; 117 | #endif 118 | } 119 | 120 | #pragma mark - 121 | 122 | - (id)delegate { 123 | return myDelegate; 124 | } 125 | 126 | #pragma mark - 127 | 128 | - (void)cancel { 129 | [myConnection cancel]; 130 | 131 | [self invalidateTimer]; 132 | } 133 | 134 | #pragma mark - 135 | 136 | - (void)dealloc { 137 | #if ! __has_feature(objc_arc) 138 | [myManager release]; 139 | [myRequest release]; 140 | [myIdentifier release]; 141 | [myData release]; 142 | [myConnection release]; 143 | [myDelegate release]; 144 | 145 | [super dealloc]; 146 | #endif 147 | } 148 | 149 | @end 150 | 151 | #pragma mark - 152 | 153 | @implementation XMLRPCConnection (XMLRPCConnectionPrivate) 154 | 155 | - (void)connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response { 156 | if([response respondsToSelector: @selector(statusCode)]) { 157 | NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; 158 | 159 | if(statusCode >= 400) { 160 | NSError *error = [NSError errorWithDomain: @"HTTP" code: statusCode userInfo: nil]; 161 | 162 | [myDelegate request: myRequest didFailWithError: error]; 163 | } else if (statusCode == 304) { 164 | [myManager closeConnectionForIdentifier: myIdentifier]; 165 | } 166 | } 167 | 168 | [myData setLength: 0]; 169 | } 170 | 171 | - (void)connection: (NSURLConnection *)connection didReceiveData: (NSData *)data { 172 | [myData appendData: data]; 173 | } 174 | 175 | - (void)connection: (NSURLConnection *)connection didSendBodyData: (NSInteger)bytesWritten totalBytesWritten: (NSInteger)totalBytesWritten totalBytesExpectedToWrite: (NSInteger)totalBytesExpectedToWrite { 176 | if ([myDelegate respondsToSelector: @selector(request:didSendBodyData:)]) { 177 | float percent = totalBytesWritten / (float)totalBytesExpectedToWrite; 178 | 179 | [myDelegate request:myRequest didSendBodyData:percent]; 180 | } 181 | } 182 | 183 | - (void)connection: (NSURLConnection *)connection didFailWithError: (NSError *)error { 184 | #if ! __has_feature(objc_arc) 185 | XMLRPCRequest *request = [[myRequest retain] autorelease]; 186 | #else 187 | XMLRPCRequest *request = myRequest; 188 | #endif 189 | 190 | NSLog(@"The connection, %@, failed with the following error: %@", myIdentifier, [error localizedDescription]); 191 | 192 | [self invalidateTimer]; 193 | 194 | [myDelegate request: request didFailWithError: error]; 195 | 196 | [myManager closeConnectionForIdentifier: myIdentifier]; 197 | } 198 | 199 | #pragma mark - 200 | 201 | - (BOOL)connection: (NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace { 202 | return [myDelegate request: myRequest canAuthenticateAgainstProtectionSpace: protectionSpace]; 203 | } 204 | 205 | - (void)connection: (NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge { 206 | [myDelegate request: myRequest didReceiveAuthenticationChallenge: challenge]; 207 | } 208 | 209 | - (void)connection: (NSURLConnection *)connection didCancelAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge { 210 | [myDelegate request: myRequest didCancelAuthenticationChallenge: challenge]; 211 | } 212 | 213 | - (void)connectionDidFinishLoading: (NSURLConnection *)connection { 214 | [self invalidateTimer]; 215 | if (myData && ([myData length] > 0)) { 216 | NSBlockOperation *parsingOperation; 217 | 218 | #if ! __has_feature(objc_arc) 219 | parsingOperation = [NSBlockOperation blockOperationWithBlock:^{ 220 | XMLRPCResponse *response = [[[XMLRPCResponse alloc] initWithData: myData] autorelease]; 221 | XMLRPCRequest *request = [[myRequest retain] autorelease]; 222 | 223 | [[NSOperationQueue mainQueue] addOperation: [NSBlockOperation blockOperationWithBlock:^{ 224 | [myDelegate request: request didReceiveResponse: response]; 225 | }]]; 226 | }]; 227 | #else 228 | parsingOperation = [NSBlockOperation blockOperationWithBlock:^{ 229 | XMLRPCResponse *response = [[XMLRPCResponse alloc] initWithData: myData]; 230 | XMLRPCRequest *request = myRequest; 231 | 232 | [[NSOperationQueue mainQueue] addOperation: [NSBlockOperation blockOperationWithBlock:^{ 233 | [myDelegate request: request didReceiveResponse: response]; 234 | 235 | [myManager closeConnectionForIdentifier: myIdentifier]; 236 | }]]; 237 | }]; 238 | #endif 239 | 240 | [[XMLRPCConnection parsingQueue] addOperation: parsingOperation]; 241 | } 242 | else { 243 | [myManager closeConnectionForIdentifier: myIdentifier]; 244 | } 245 | } 246 | 247 | #pragma mark - 248 | - (void)timeoutExpired 249 | { 250 | NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: 251 | [myRequest URL], NSURLErrorFailingURLErrorKey, 252 | [[myRequest URL] absoluteString], NSURLErrorFailingURLStringErrorKey, 253 | //TODO not good to use hardcoded value for localized description 254 | @"The request timed out.", NSLocalizedDescriptionKey, 255 | nil]; 256 | 257 | NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:userInfo]; 258 | 259 | [self connection:myConnection didFailWithError:error]; 260 | } 261 | 262 | - (void)invalidateTimer 263 | { 264 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeoutExpired) object:nil]; 265 | } 266 | 267 | #pragma mark - 268 | 269 | + (NSOperationQueue *)parsingQueue { 270 | if (parsingQueue == nil) { 271 | parsingQueue = [[NSOperationQueue alloc] init]; 272 | } 273 | 274 | return parsingQueue; 275 | } 276 | 277 | @end 278 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCConnectionDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class XMLRPCConnection, XMLRPCRequest, XMLRPCResponse; 4 | 5 | @protocol XMLRPCConnectionDelegate 6 | 7 | @required 8 | - (void)request: (XMLRPCRequest *)request didReceiveResponse: (XMLRPCResponse *)response; 9 | 10 | @optional 11 | - (void)request: (XMLRPCRequest *)request didSendBodyData: (float)percent; 12 | 13 | @required 14 | - (void)request: (XMLRPCRequest *)request didFailWithError: (NSError *)error; 15 | 16 | #pragma mark - 17 | 18 | @required 19 | - (BOOL)request: (XMLRPCRequest *)request canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace; 20 | 21 | @required 22 | - (void)request: (XMLRPCRequest *)request didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge; 23 | 24 | @required 25 | - (void)request: (XMLRPCRequest *)request didCancelAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCConnectionManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "XMLRPCConnectionDelegate.h" 3 | 4 | @class XMLRPCConnection, XMLRPCRequest; 5 | 6 | @interface XMLRPCConnectionManager : NSObject { 7 | NSMutableDictionary *myConnections; 8 | } 9 | 10 | + (XMLRPCConnectionManager *)sharedManager; 11 | 12 | #pragma mark - 13 | 14 | - (NSString *)spawnConnectionWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate; 15 | 16 | #pragma mark - 17 | 18 | - (NSArray *)activeConnectionIdentifiers; 19 | 20 | - (NSUInteger)numberOfActiveConnections; 21 | 22 | #pragma mark - 23 | 24 | - (XMLRPCConnection *)connectionForIdentifier: (NSString *)identifier; 25 | 26 | #pragma mark - 27 | 28 | - (void)closeConnectionForIdentifier: (NSString *)identifier; 29 | 30 | - (void)closeConnections; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCConnectionManager.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCConnectionManager.h" 2 | #import "XMLRPCConnection.h" 3 | #import "XMLRPCRequest.h" 4 | 5 | @implementation XMLRPCConnectionManager 6 | 7 | static XMLRPCConnectionManager *sharedInstance = nil; 8 | 9 | - (id)init { 10 | self = [super init]; 11 | if (self) { 12 | myConnections = [[NSMutableDictionary alloc] init]; 13 | } 14 | 15 | return self; 16 | } 17 | 18 | #pragma mark - 19 | 20 | + (id)allocWithZone: (NSZone *)zone { 21 | @synchronized(self) { 22 | if (!sharedInstance) { 23 | sharedInstance = [super allocWithZone: zone]; 24 | 25 | return sharedInstance; 26 | } 27 | } 28 | 29 | return nil; 30 | } 31 | 32 | #pragma mark - 33 | 34 | + (XMLRPCConnectionManager *)sharedManager { 35 | @synchronized(self) { 36 | if (!sharedInstance) { 37 | sharedInstance = [[self alloc] init]; 38 | } 39 | } 40 | 41 | return sharedInstance; 42 | } 43 | 44 | #pragma mark - 45 | 46 | - (NSString *)spawnConnectionWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate { 47 | XMLRPCConnection *newConnection = [[XMLRPCConnection alloc] initWithXMLRPCRequest: request delegate: delegate manager: self]; 48 | #if ! __has_feature(objc_arc) 49 | NSString *identifier = [[[newConnection identifier] retain] autorelease]; 50 | #else 51 | NSString *identifier = [newConnection identifier]; 52 | #endif 53 | 54 | [myConnections setObject: newConnection forKey: identifier]; 55 | 56 | #if ! __has_feature(objc_arc) 57 | [newConnection release]; 58 | #endif 59 | 60 | return identifier; 61 | } 62 | 63 | #pragma mark - 64 | 65 | - (NSArray *)activeConnectionIdentifiers { 66 | return [myConnections allKeys]; 67 | } 68 | 69 | - (NSUInteger)numberOfActiveConnections { 70 | return [myConnections count]; 71 | } 72 | 73 | #pragma mark - 74 | 75 | - (XMLRPCConnection *)connectionForIdentifier: (NSString *)identifier { 76 | return [myConnections objectForKey: identifier]; 77 | } 78 | 79 | #pragma mark - 80 | 81 | - (void)closeConnectionForIdentifier: (NSString *)identifier { 82 | XMLRPCConnection *selectedConnection = [self connectionForIdentifier: identifier]; 83 | 84 | if (selectedConnection) { 85 | [selectedConnection cancel]; 86 | 87 | [myConnections removeObjectForKey: identifier]; 88 | } 89 | } 90 | 91 | - (void)closeConnections { 92 | [[myConnections allValues] makeObjectsPerformSelector: @selector(cancel)]; 93 | 94 | [myConnections removeAllObjects]; 95 | } 96 | 97 | #pragma mark - 98 | 99 | 100 | #pragma mark - 101 | 102 | - (void)dealloc { 103 | [self closeConnections]; 104 | 105 | #if ! __has_feature(objc_arc) 106 | [myConnections release]; 107 | 108 | [super dealloc]; 109 | #endif 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCDefaultEncoder.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "XMLRPCEncoder.h" 3 | 4 | @interface XMLRPCDefaultEncoder : NSObject { 5 | NSString *myMethod; 6 | NSArray *myParameters; 7 | } 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCDefaultEncoder.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCDefaultEncoder.h" 2 | #import "NSStringAdditions.h" 3 | #import "NSData+Base64.h" 4 | 5 | @interface XMLRPCDefaultEncoder (XMLRPCEncoderPrivate) 6 | 7 | - (NSString *)valueTag: (NSString *)tag value: (NSString *)value; 8 | 9 | #pragma mark - 10 | 11 | - (NSString *)replaceTarget: (NSString *)target withValue: (NSString *)value inString: (NSString *)string; 12 | 13 | #pragma mark - 14 | 15 | - (NSString *)encodeObject: (id)object; 16 | 17 | #pragma mark - 18 | 19 | - (NSString *)encodeArray: (NSArray *)array; 20 | 21 | - (NSString *)encodeDictionary: (NSDictionary *)dictionary; 22 | 23 | #pragma mark - 24 | 25 | - (NSString *)encodeBoolean: (CFBooleanRef)boolean; 26 | 27 | - (NSString *)encodeNumber: (NSNumber *)number; 28 | 29 | - (NSString *)encodeString: (NSString *)string omitTag: (BOOL)omitTag; 30 | 31 | - (NSString *)encodeDate: (NSDate *)date; 32 | 33 | - (NSString *)encodeData: (NSData *)data; 34 | 35 | @end 36 | 37 | #pragma mark - 38 | 39 | @implementation XMLRPCDefaultEncoder 40 | 41 | - (id)init { 42 | if (self = [super init]) { 43 | myMethod = [[NSString alloc] init]; 44 | myParameters = [[NSArray alloc] init]; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | #pragma mark - 51 | 52 | - (NSString *)encode { 53 | NSMutableString *buffer = [NSMutableString stringWithString: @""]; 54 | 55 | [buffer appendFormat: @"%@", [self encodeString: myMethod omitTag: YES]]; 56 | 57 | [buffer appendString: @""]; 58 | 59 | if (myParameters) { 60 | NSEnumerator *enumerator = [myParameters objectEnumerator]; 61 | id parameter = nil; 62 | 63 | while ((parameter = [enumerator nextObject])) { 64 | [buffer appendString: @""]; 65 | [buffer appendString: [self encodeObject: parameter]]; 66 | [buffer appendString: @""]; 67 | } 68 | } 69 | 70 | [buffer appendString: @""]; 71 | 72 | [buffer appendString: @""]; 73 | 74 | return buffer; 75 | } 76 | 77 | #pragma mark - 78 | 79 | - (void)setMethod: (NSString *)method withParameters: (NSArray *)parameters { 80 | #if ! __has_feature(objc_arc) 81 | if (myMethod) { 82 | [myMethod release]; 83 | } 84 | 85 | if (!method) { 86 | myMethod = nil; 87 | } else { 88 | myMethod = [method retain]; 89 | } 90 | 91 | if (myParameters) { 92 | [myParameters release]; 93 | } 94 | 95 | if (!parameters) { 96 | myParameters = nil; 97 | } else { 98 | myParameters = [parameters retain]; 99 | } 100 | #else 101 | myMethod = method; 102 | myParameters = parameters; 103 | #endif 104 | } 105 | 106 | #pragma mark - 107 | 108 | - (NSString *)method { 109 | return myMethod; 110 | } 111 | 112 | - (NSArray *)parameters { 113 | return myParameters; 114 | } 115 | 116 | #pragma mark - 117 | 118 | - (void)dealloc { 119 | #if ! __has_feature(objc_arc) 120 | [myMethod release]; 121 | [myParameters release]; 122 | 123 | [super dealloc]; 124 | #endif 125 | } 126 | 127 | @end 128 | 129 | #pragma mark - 130 | 131 | @implementation XMLRPCDefaultEncoder (XMLRPCEncoderPrivate) 132 | 133 | - (NSString *)valueTag: (NSString *)tag value: (NSString *)value { 134 | return [NSString stringWithFormat: @"<%@>%@", tag, value, tag]; 135 | } 136 | 137 | #pragma mark - 138 | 139 | - (NSString *)replaceTarget: (NSString *)target withValue: (NSString *)value inString: (NSString *)string { 140 | return [[string componentsSeparatedByString: target] componentsJoinedByString: value]; 141 | } 142 | 143 | #pragma mark - 144 | 145 | - (NSString *)encodeObject: (id)object { 146 | if (!object) { 147 | return nil; 148 | } 149 | 150 | if ([object isKindOfClass: [NSArray class]]) { 151 | return [self encodeArray: object]; 152 | } else if ([object isKindOfClass: [NSDictionary class]]) { 153 | return [self encodeDictionary: object]; 154 | #if ! __has_feature(objc_arc) 155 | } else if (((CFBooleanRef)object == kCFBooleanTrue) || ((CFBooleanRef)object == kCFBooleanFalse)) { 156 | #else 157 | } else if (((__bridge CFBooleanRef)object == kCFBooleanTrue) || ((__bridge CFBooleanRef)object == kCFBooleanFalse)) { 158 | #endif 159 | return [self encodeBoolean: (CFBooleanRef)object]; 160 | } else if ([object isKindOfClass: [NSNumber class]]) { 161 | return [self encodeNumber: object]; 162 | } else if ([object isKindOfClass: [NSString class]]) { 163 | return [self encodeString: object omitTag: NO]; 164 | } else if ([object isKindOfClass: [NSDate class]]) { 165 | return [self encodeDate: object]; 166 | } else if ([object isKindOfClass: [NSData class]]) { 167 | return [self encodeData: object]; 168 | } else { 169 | return [self encodeString: object omitTag: NO]; 170 | } 171 | } 172 | 173 | #pragma mark - 174 | 175 | - (NSString *)encodeArray: (NSArray *)array { 176 | NSMutableString *buffer = [NSMutableString string]; 177 | NSEnumerator *enumerator = [array objectEnumerator]; 178 | 179 | [buffer appendString: @""]; 180 | 181 | id object = nil; 182 | 183 | while (object = [enumerator nextObject]) { 184 | [buffer appendString: [self encodeObject: object]]; 185 | } 186 | 187 | [buffer appendString: @""]; 188 | 189 | return (NSString *)buffer; 190 | } 191 | 192 | - (NSString *)encodeDictionary: (NSDictionary *)dictionary { 193 | NSMutableString * buffer = [NSMutableString string]; 194 | NSEnumerator *enumerator = [dictionary keyEnumerator]; 195 | 196 | [buffer appendString: @""]; 197 | 198 | NSString *key = nil; 199 | NSObject *val; 200 | 201 | while (key = [enumerator nextObject]) { 202 | [buffer appendString: @""]; 203 | [buffer appendFormat: @"%@", [self encodeString: key omitTag: YES]]; 204 | 205 | val = [dictionary objectForKey: key]; 206 | if (val != [NSNull null]) { 207 | [buffer appendString: [self encodeObject: val]]; 208 | } else { 209 | [buffer appendString:@""]; 210 | } 211 | 212 | [buffer appendString: @""]; 213 | } 214 | 215 | [buffer appendString: @""]; 216 | 217 | return (NSString *)buffer; 218 | } 219 | 220 | #pragma mark - 221 | 222 | - (NSString *)encodeBoolean: (CFBooleanRef)boolean { 223 | if (boolean == kCFBooleanTrue) { 224 | return [self valueTag: @"boolean" value: @"1"]; 225 | } else { 226 | return [self valueTag: @"boolean" value: @"0"]; 227 | } 228 | } 229 | 230 | - (NSString *)encodeNumber: (NSNumber *)number { 231 | NSString *numberType = [NSString stringWithCString: [number objCType] encoding: NSUTF8StringEncoding]; 232 | 233 | if ([numberType isEqualToString: @"d"]) { 234 | return [self valueTag: @"double" value: [number stringValue]]; 235 | } else { 236 | return [self valueTag: @"i4" value: [number stringValue]]; 237 | } 238 | } 239 | 240 | - (NSString *)encodeString: (NSString *)string omitTag: (BOOL)omitTag { 241 | return omitTag ? [string escapedString] : [self valueTag: @"string" value: [string escapedString]]; 242 | } 243 | 244 | - (NSString *)encodeDate: (NSDate *)date { 245 | unsigned components = kCFCalendarUnitYear | kCFCalendarUnitMonth | kCFCalendarUnitDay | kCFCalendarUnitHour | kCFCalendarUnitMinute | kCFCalendarUnitSecond; 246 | NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components: components fromDate: date]; 247 | NSString *buffer = [NSString stringWithFormat: @"%.4ld%.2ld%.2ldT%.2ld:%.2ld:%.2ld", (long)[dateComponents year], (long)[dateComponents month], (long)[dateComponents day], (long)[dateComponents hour], (long)[dateComponents minute], (long)[dateComponents second], nil]; 248 | 249 | return [self valueTag: @"dateTime.iso8601" value: buffer]; 250 | } 251 | 252 | - (NSString *)encodeData: (NSData *)data { 253 | return [self valueTag: @"base64" value: [data base64EncodedString]]; 254 | } 255 | 256 | @end 257 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCEncoder.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol XMLRPCEncoder 4 | 5 | - (NSString *)encode; 6 | 7 | #pragma mark - 8 | 9 | - (void)setMethod: (NSString *)method withParameters: (NSArray *)parameters; 10 | 11 | #pragma mark - 12 | 13 | - (NSString *)method; 14 | 15 | - (NSArray *)parameters; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCEventBasedParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class XMLRPCEventBasedParserDelegate; 4 | 5 | @interface XMLRPCEventBasedParser : NSObject { 6 | NSXMLParser *myParser; 7 | XMLRPCEventBasedParserDelegate *myParserDelegate; 8 | BOOL isFault; 9 | } 10 | 11 | - (id)initWithData: (NSData *)data; 12 | 13 | #pragma mark - 14 | 15 | - (id)parse; 16 | 17 | - (void)abortParsing; 18 | 19 | #pragma mark - 20 | 21 | - (NSError *)parserError; 22 | 23 | #pragma mark - 24 | 25 | - (BOOL)isFault; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCEventBasedParser.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCEventBasedParser.h" 2 | #import "XMLRPCEventBasedParserDelegate.h" 3 | 4 | @implementation XMLRPCEventBasedParser 5 | 6 | - (id)initWithData: (NSData *)data { 7 | if (!data) { 8 | return nil; 9 | } 10 | 11 | if (self = [self init]) { 12 | myParser = [[NSXMLParser alloc] initWithData: data]; 13 | myParserDelegate = nil; 14 | isFault = NO; 15 | } 16 | 17 | return self; 18 | } 19 | 20 | #pragma mark - 21 | 22 | - (id)parse { 23 | [myParser setDelegate: self]; 24 | 25 | [myParser parse]; 26 | 27 | if ([myParser parserError]) { 28 | return nil; 29 | } 30 | 31 | return [myParserDelegate elementValue]; 32 | } 33 | 34 | - (void)abortParsing { 35 | [myParser abortParsing]; 36 | } 37 | 38 | #pragma mark - 39 | 40 | - (NSError *)parserError { 41 | return [myParser parserError]; 42 | } 43 | 44 | #pragma mark - 45 | 46 | - (BOOL)isFault { 47 | return isFault; 48 | } 49 | 50 | #pragma mark - 51 | 52 | - (void)dealloc { 53 | #if ! __has_feature(objc_arc) 54 | [myParser release]; 55 | [myParserDelegate release]; 56 | 57 | [super dealloc]; 58 | #endif 59 | } 60 | 61 | @end 62 | 63 | #pragma mark - 64 | 65 | @implementation XMLRPCEventBasedParser (NSXMLParserDelegate) 66 | 67 | - (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)element namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qualifiedName attributes: (NSDictionary *)attributes { 68 | if ([element isEqualToString: @"fault"]) { 69 | isFault = YES; 70 | } else if ([element isEqualToString: @"value"]) { 71 | myParserDelegate = [[XMLRPCEventBasedParserDelegate alloc] initWithParent: nil]; 72 | 73 | [myParser setDelegate: myParserDelegate]; 74 | } 75 | } 76 | 77 | - (void)parser: (NSXMLParser *)parser parseErrorOccurred: (NSError *)parseError { 78 | [self abortParsing]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCEventBasedParserDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef enum { 4 | XMLRPCElementTypeArray, 5 | XMLRPCElementTypeDictionary, 6 | XMLRPCElementTypeMember, 7 | XMLRPCElementTypeName, 8 | XMLRPCElementTypeInteger, 9 | XMLRPCElementTypeDouble, 10 | XMLRPCElementTypeBoolean, 11 | XMLRPCElementTypeString, 12 | XMLRPCElementTypeDate, 13 | XMLRPCElementTypeData 14 | } XMLRPCElementType; 15 | 16 | #pragma mark - 17 | 18 | @interface XMLRPCEventBasedParserDelegate : NSObject { 19 | #if !__has_feature(objc_arc) 20 | XMLRPCEventBasedParserDelegate *myParent; 21 | #else 22 | // Without ARC this reference is effectively unretained so don't use strong reference here. 23 | XMLRPCEventBasedParserDelegate * __unsafe_unretained myParent; 24 | #endif 25 | NSMutableSet *myChildren; 26 | XMLRPCElementType myElementType; 27 | NSString *myElementKey; 28 | id myElementValue; 29 | } 30 | 31 | - (id)initWithParent: (XMLRPCEventBasedParserDelegate *)parent; 32 | 33 | #pragma mark - 34 | 35 | - (void)setParent: (XMLRPCEventBasedParserDelegate *)parent; 36 | 37 | - (XMLRPCEventBasedParserDelegate *)parent; 38 | 39 | #pragma mark - 40 | 41 | - (void)setElementType: (XMLRPCElementType)elementType; 42 | 43 | - (XMLRPCElementType)elementType; 44 | 45 | #pragma mark - 46 | 47 | - (void)setElementKey: (NSString *)elementKey; 48 | 49 | - (NSString *)elementKey; 50 | 51 | #pragma mark - 52 | 53 | - (void)setElementValue: (id)elementValue; 54 | 55 | - (id)elementValue; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCEventBasedParserDelegate.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCEventBasedParserDelegate.h" 2 | #import "NSData+Base64.h" 3 | 4 | @interface XMLRPCEventBasedParserDelegate (XMLRPCEventBasedParserDelegatePrivate) 5 | 6 | - (BOOL)isDictionaryElementType: (XMLRPCElementType)elementType; 7 | 8 | #pragma mark - 9 | 10 | - (void)addElementValueToParent; 11 | 12 | #pragma mark - 13 | 14 | - (NSDate *)parseDateString: (NSString *)dateString withFormat: (NSString *)format; 15 | 16 | #pragma mark - 17 | 18 | - (NSNumber *)parseInteger: (NSString *)value; 19 | 20 | - (NSNumber *)parseDouble: (NSString *)value; 21 | 22 | - (NSNumber *)parseBoolean: (NSString *)value; 23 | 24 | - (NSString *)parseString: (NSString *)value; 25 | 26 | - (NSDate *)parseDate: (NSString *)value; 27 | 28 | - (NSData *)parseData: (NSString *)value; 29 | 30 | @end 31 | 32 | #pragma mark - 33 | 34 | @implementation XMLRPCEventBasedParserDelegate 35 | 36 | - (id)initWithParent: (XMLRPCEventBasedParserDelegate *)parent { 37 | self = [super init]; 38 | if (self) { 39 | myParent = parent; 40 | myChildren = [[NSMutableSet alloc] initWithCapacity: 1]; 41 | myElementType = XMLRPCElementTypeString; 42 | myElementKey = nil; 43 | myElementValue = [[NSMutableString alloc] init]; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | #pragma mark - 50 | 51 | - (void)setParent: (XMLRPCEventBasedParserDelegate *)parent { 52 | #if ! __has_feature(objc_arc) 53 | [parent retain]; 54 | [myParent release]; 55 | #endif 56 | 57 | myParent = parent; 58 | } 59 | 60 | - (XMLRPCEventBasedParserDelegate *)parent { 61 | return myParent; 62 | } 63 | 64 | #pragma mark - 65 | 66 | - (void)setElementType: (XMLRPCElementType)elementType { 67 | myElementType = elementType; 68 | } 69 | 70 | - (XMLRPCElementType)elementType { 71 | return myElementType; 72 | } 73 | 74 | #pragma mark - 75 | 76 | - (void)setElementKey: (NSString *)elementKey { 77 | #if ! __has_feature(objc_arc) 78 | [elementKey retain]; 79 | [myElementKey release]; 80 | #endif 81 | 82 | myElementKey = elementKey; 83 | } 84 | 85 | - (NSString *)elementKey { 86 | return myElementKey; 87 | } 88 | 89 | #pragma mark - 90 | 91 | - (void)setElementValue: (id)elementValue { 92 | #if ! __has_feature(objc_arc) 93 | [elementValue retain]; 94 | [myElementValue release]; 95 | #endif 96 | 97 | myElementValue = elementValue; 98 | } 99 | 100 | - (id)elementValue { 101 | return myElementValue; 102 | } 103 | 104 | #pragma mark - 105 | 106 | - (void)dealloc { 107 | #if ! __has_feature(objc_arc) 108 | [myChildren release]; 109 | [myElementKey release]; 110 | [myElementValue release]; 111 | 112 | [super dealloc]; 113 | #endif 114 | } 115 | 116 | @end 117 | 118 | #pragma mark - 119 | 120 | @implementation XMLRPCEventBasedParserDelegate (NSXMLParserDelegate) 121 | 122 | - (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)element namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qualifiedName attributes: (NSDictionary *)attributes { 123 | if ([element isEqualToString: @"value"] || [element isEqualToString: @"member"] || [element isEqualToString: @"name"]) { 124 | XMLRPCEventBasedParserDelegate *parserDelegate = [[XMLRPCEventBasedParserDelegate alloc] initWithParent: self]; 125 | 126 | if ([element isEqualToString: @"member"]) { 127 | [parserDelegate setElementType: XMLRPCElementTypeMember]; 128 | } else if ([element isEqualToString: @"name"]) { 129 | [parserDelegate setElementType: XMLRPCElementTypeName]; 130 | } 131 | 132 | [myChildren addObject: parserDelegate]; 133 | 134 | [parser setDelegate: parserDelegate]; 135 | #if ! __has_feature(objc_arc) 136 | [parserDelegate release]; 137 | #endif 138 | return; 139 | } 140 | 141 | if ([element isEqualToString: @"array"]) { 142 | NSMutableArray *array = [[NSMutableArray alloc] init]; 143 | 144 | [self setElementValue: array]; 145 | #if ! __has_feature(objc_arc) 146 | [array release]; 147 | #endif 148 | [self setElementType: XMLRPCElementTypeArray]; 149 | } else if ([element isEqualToString: @"struct"]) { 150 | NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; 151 | 152 | [self setElementValue: dictionary]; 153 | #if ! __has_feature(objc_arc) 154 | [dictionary release]; 155 | #endif 156 | [self setElementType: XMLRPCElementTypeDictionary]; 157 | } else if ([element isEqualToString: @"int"] || [element isEqualToString: @"i4"]) { 158 | [self setElementType: XMLRPCElementTypeInteger]; 159 | } else if ([element isEqualToString: @"double"]) { 160 | [self setElementType: XMLRPCElementTypeDouble]; 161 | } else if ([element isEqualToString: @"boolean"]) { 162 | [self setElementType: XMLRPCElementTypeBoolean]; 163 | } else if ([element isEqualToString: @"string"]) { 164 | [self setElementType: XMLRPCElementTypeString]; 165 | } else if ([element isEqualToString: @"dateTime.iso8601"]) { 166 | [self setElementType: XMLRPCElementTypeDate]; 167 | } else if ([element isEqualToString: @"base64"]) { 168 | [self setElementType: XMLRPCElementTypeData]; 169 | } 170 | } 171 | 172 | - (void)parser: (NSXMLParser *)parser didEndElement: (NSString *)element namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qualifiedName { 173 | if ([element isEqualToString: @"value"] || [element isEqualToString: @"member"] || [element isEqualToString: @"name"]) { 174 | NSString *elementValue = nil; 175 | 176 | if ((myElementType != XMLRPCElementTypeArray) && ![self isDictionaryElementType: myElementType]) { 177 | elementValue = [self parseString: myElementValue]; 178 | #if ! __has_feature(objc_arc) 179 | [myElementValue release]; 180 | #endif 181 | myElementValue = nil; 182 | } 183 | 184 | switch (myElementType) { 185 | case XMLRPCElementTypeInteger: 186 | myElementValue = [self parseInteger: elementValue]; 187 | #if ! __has_feature(objc_arc) 188 | [myElementValue retain]; 189 | #endif 190 | break; 191 | case XMLRPCElementTypeDouble: 192 | myElementValue = [self parseDouble: elementValue]; 193 | #if ! __has_feature(objc_arc) 194 | [myElementValue retain]; 195 | #endif 196 | break; 197 | case XMLRPCElementTypeBoolean: 198 | myElementValue = [self parseBoolean: elementValue]; 199 | #if ! __has_feature(objc_arc) 200 | [myElementValue retain]; 201 | #endif 202 | break; 203 | case XMLRPCElementTypeString: 204 | case XMLRPCElementTypeName: 205 | myElementValue = elementValue; 206 | #if ! __has_feature(objc_arc) 207 | [myElementValue retain]; 208 | #endif 209 | break; 210 | case XMLRPCElementTypeDate: 211 | myElementValue = [self parseDate: elementValue]; 212 | #if ! __has_feature(objc_arc) 213 | [myElementValue retain]; 214 | #endif 215 | break; 216 | case XMLRPCElementTypeData: 217 | myElementValue = [self parseData: elementValue]; 218 | #if ! __has_feature(objc_arc) 219 | [myElementValue retain]; 220 | #endif 221 | break; 222 | default: 223 | break; 224 | } 225 | 226 | if (myParent && myElementValue) { 227 | [self addElementValueToParent]; 228 | } 229 | 230 | [parser setDelegate: myParent]; 231 | 232 | if (myParent) { 233 | XMLRPCEventBasedParserDelegate *parent = myParent; 234 | 235 | // Set it to nil explicitly since it's not __weak but __unsafe_unretained. 236 | // We're doing it here because if we'll do it after removal from myChildren 237 | // self can already be deallocated, and accessing field of deallocated object 238 | // causes memory corruption. 239 | myParent = nil; 240 | 241 | [parent->myChildren removeObject: self]; 242 | } 243 | } 244 | } 245 | 246 | - (void)parser: (NSXMLParser *)parser foundCharacters: (NSString *)string { 247 | if ((myElementType == XMLRPCElementTypeArray) || [self isDictionaryElementType: myElementType]) { 248 | return; 249 | } 250 | 251 | if (!myElementValue) { 252 | myElementValue = [[NSMutableString alloc] initWithString: string]; 253 | } else { 254 | [myElementValue appendString: string]; 255 | } 256 | } 257 | 258 | - (void)parser: (NSXMLParser *)parser parseErrorOccurred: (NSError *)parseError { 259 | [parser abortParsing]; 260 | } 261 | 262 | @end 263 | 264 | #pragma mark - 265 | 266 | @implementation XMLRPCEventBasedParserDelegate (XMLRPCEventBasedParserDelegatePrivate) 267 | 268 | - (BOOL)isDictionaryElementType: (XMLRPCElementType)elementType { 269 | if ((myElementType == XMLRPCElementTypeDictionary) || (myElementType == XMLRPCElementTypeMember)) { 270 | return YES; 271 | } 272 | 273 | return NO; 274 | } 275 | 276 | #pragma mark - 277 | 278 | - (void)addElementValueToParent { 279 | id parentElementValue = [myParent elementValue]; 280 | 281 | switch ([myParent elementType]) { 282 | case XMLRPCElementTypeArray: 283 | [parentElementValue addObject: myElementValue]; 284 | 285 | break; 286 | case XMLRPCElementTypeDictionary: 287 | if ([myElementValue isEqual:[NSNull null]]) { 288 | [parentElementValue removeObjectForKey:myElementKey]; 289 | } else { 290 | [parentElementValue setObject: myElementValue forKey: myElementKey]; 291 | } 292 | 293 | break; 294 | case XMLRPCElementTypeMember: 295 | if (myElementType == XMLRPCElementTypeName) { 296 | [myParent setElementKey: myElementValue]; 297 | } else { 298 | [myParent setElementValue: myElementValue]; 299 | } 300 | 301 | break; 302 | default: 303 | break; 304 | } 305 | } 306 | 307 | #pragma mark - 308 | 309 | - (NSDate *)parseDateString: (NSString *)dateString withFormat: (NSString *)format { 310 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 311 | NSDate *result = nil; 312 | 313 | [dateFormatter setDateFormat: format]; 314 | 315 | result = [dateFormatter dateFromString: dateString]; 316 | #if ! __has_feature(objc_arc) 317 | [dateFormatter release]; 318 | #endif 319 | return result; 320 | } 321 | 322 | #pragma mark - 323 | 324 | - (NSNumber *)parseInteger: (NSString *)value { 325 | return [NSNumber numberWithInteger: [value integerValue]]; 326 | } 327 | 328 | - (NSNumber *)parseDouble: (NSString *)value { 329 | return [NSNumber numberWithDouble: [value doubleValue]]; 330 | } 331 | 332 | - (NSNumber *)parseBoolean: (NSString *)value { 333 | if ([value isEqualToString: @"1"]) { 334 | return [NSNumber numberWithBool: YES]; 335 | } 336 | 337 | return [NSNumber numberWithBool: NO]; 338 | } 339 | 340 | - (NSString *)parseString: (NSString *)value { 341 | return [value stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 342 | } 343 | 344 | - (NSDate *)parseDate: (NSString *)value { 345 | NSDate *result = nil; 346 | 347 | result = [self parseDateString: value withFormat: @"yyyyMMdd'T'HH:mm:ss"]; 348 | 349 | if (!result) { 350 | result = [self parseDateString: value withFormat: @"yyyy'-'MM'-'dd'T'HH:mm:ss"]; 351 | } 352 | 353 | if (!result) { 354 | result = [self parseDateString: value withFormat: @"yyyy'-'MM'-'dd'T'HH:mm:ssZ"]; 355 | } 356 | 357 | if (!result) { 358 | result = (NSDate *)[NSNull null]; 359 | } 360 | 361 | return result; 362 | } 363 | 364 | - (NSData *)parseData: (NSString *)value { 365 | return [NSData dataFromBase64String: value]; 366 | } 367 | 368 | @end 369 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCRequest.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "XMLRPCEncoder.h" 4 | 5 | @interface XMLRPCRequest : NSObject { 6 | NSMutableURLRequest *myRequest; 7 | id myXMLEncoder; 8 | NSTimeInterval myTimeout; 9 | 10 | id extra; 11 | } 12 | 13 | - (id)initWithURL: (NSURL *)URL; 14 | 15 | #pragma mark - 16 | 17 | - (void)setURL: (NSURL *)URL; 18 | 19 | - (NSURL *)URL; 20 | 21 | #pragma mark - 22 | 23 | - (void)setUserAgent: (NSString *)userAgent; 24 | 25 | - (NSString *)userAgent; 26 | 27 | #pragma mark - 28 | 29 | - (void)setEncoder: (id) encoder; 30 | 31 | - (void)setMethod: (NSString *)method; 32 | 33 | - (void)setMethod: (NSString *)method withParameter: (id)parameter; 34 | 35 | - (void)setMethod: (NSString *)method withParameters: (NSArray *)parameters; 36 | 37 | - (void)setTimeoutInterval: (NSTimeInterval)timeout; 38 | 39 | #pragma mark - 40 | 41 | - (NSString *)method; 42 | 43 | - (NSArray *)parameters; 44 | 45 | - (NSTimeInterval)timeout; 46 | 47 | #pragma mark - 48 | 49 | - (NSString *)body; 50 | 51 | #pragma mark - 52 | 53 | - (NSURLRequest *)request; 54 | 55 | #pragma mark - 56 | 57 | - (void)setValue: (NSString *)value forHTTPHeaderField: (NSString *)header; 58 | 59 | #pragma mark - 60 | 61 | - (id) extra; 62 | - (void) setExtra:(id) extraObject; 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCRequest.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCRequest.h" 2 | #import "XMLRPCEncoder.h" 3 | #import "XMLRPCDefaultEncoder.h" 4 | 5 | static const NSTimeInterval DEFAULT_TIMEOUT = 240; 6 | 7 | @implementation XMLRPCRequest 8 | 9 | - (id)initWithURL: (NSURL *)URL withEncoder: (id)encoder { 10 | self = [super init]; 11 | if (self) { 12 | if (URL) { 13 | myRequest = [[NSMutableURLRequest alloc] initWithURL: URL]; 14 | } else { 15 | myRequest = [[NSMutableURLRequest alloc] init]; 16 | } 17 | 18 | myXMLEncoder = encoder; 19 | #if ! __has_feature(objc_arc) 20 | [myXMLEncoder retain]; 21 | #endif 22 | 23 | myTimeout = DEFAULT_TIMEOUT; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | - (id)initWithURL: (NSURL *)URL { 30 | #if ! __has_feature(objc_arc) 31 | return [self initWithURL:URL withEncoder:[[[XMLRPCDefaultEncoder alloc] init] autorelease]]; 32 | #else 33 | return [self initWithURL:URL withEncoder:[[XMLRPCDefaultEncoder alloc] init]]; 34 | #endif 35 | } 36 | 37 | #pragma mark - 38 | 39 | - (void)setURL: (NSURL *)URL { 40 | [myRequest setURL: URL]; 41 | } 42 | 43 | - (NSURL *)URL { 44 | return [myRequest URL]; 45 | } 46 | 47 | #pragma mark - 48 | 49 | - (void)setUserAgent: (NSString *)userAgent { 50 | if (![self userAgent]) { 51 | [myRequest addValue: userAgent forHTTPHeaderField: @"User-Agent"]; 52 | } else { 53 | [myRequest setValue: userAgent forHTTPHeaderField: @"User-Agent"]; 54 | } 55 | } 56 | 57 | - (NSString *)userAgent { 58 | return [myRequest valueForHTTPHeaderField: @"User-Agent"]; 59 | } 60 | 61 | #pragma mark - 62 | 63 | - (void)setEncoder:(id)encoder { 64 | NSString *method = [myXMLEncoder method]; 65 | NSArray *parameters = [myXMLEncoder parameters]; 66 | #if ! __has_feature(objc_arc) 67 | [myXMLEncoder release]; 68 | 69 | myXMLEncoder = [encoder retain]; 70 | #else 71 | myXMLEncoder = encoder; 72 | #endif 73 | 74 | [myXMLEncoder setMethod: method withParameters: parameters]; 75 | } 76 | 77 | - (void)setMethod: (NSString *)method { 78 | [myXMLEncoder setMethod: method withParameters: nil]; 79 | } 80 | 81 | - (void)setMethod: (NSString *)method withParameter: (id)parameter { 82 | NSArray *parameters = nil; 83 | 84 | if (parameter) { 85 | parameters = [NSArray arrayWithObject: parameter]; 86 | } 87 | 88 | [myXMLEncoder setMethod: method withParameters: parameters]; 89 | } 90 | 91 | - (void)setMethod: (NSString *)method withParameters: (NSArray *)parameters { 92 | [myXMLEncoder setMethod: method withParameters: parameters]; 93 | } 94 | 95 | - (void)setTimeoutInterval: (NSTimeInterval)timeout 96 | { 97 | myTimeout = timeout; 98 | } 99 | 100 | #pragma mark - 101 | 102 | - (NSString *)method { 103 | return [myXMLEncoder method]; 104 | } 105 | 106 | - (NSArray *)parameters { 107 | return [myXMLEncoder parameters]; 108 | } 109 | 110 | - (NSTimeInterval)timeout 111 | { 112 | return myTimeout; 113 | } 114 | 115 | #pragma mark - 116 | 117 | - (NSString *)body { 118 | return [myXMLEncoder encode]; 119 | } 120 | 121 | #pragma mark - 122 | 123 | - (NSURLRequest *)request { 124 | NSData *content = [[self body] dataUsingEncoding: NSUTF8StringEncoding]; 125 | NSNumber *contentLength = [NSNumber numberWithUnsignedInteger:[content length]]; 126 | 127 | if (!myRequest) { 128 | return nil; 129 | } 130 | 131 | [myRequest setHTTPMethod: @"POST"]; 132 | 133 | if (![myRequest valueForHTTPHeaderField: @"Content-Type"]) { 134 | [myRequest addValue: @"text/xml" forHTTPHeaderField: @"Content-Type"]; 135 | } else { 136 | [myRequest setValue: @"text/xml" forHTTPHeaderField: @"Content-Type"]; 137 | } 138 | 139 | if (![myRequest valueForHTTPHeaderField: @"Content-Length"]) { 140 | [myRequest addValue: [contentLength stringValue] forHTTPHeaderField: @"Content-Length"]; 141 | } else { 142 | [myRequest setValue: [contentLength stringValue] forHTTPHeaderField: @"Content-Length"]; 143 | } 144 | 145 | if (![myRequest valueForHTTPHeaderField: @"Accept"]) { 146 | [myRequest addValue: @"text/xml" forHTTPHeaderField: @"Accept"]; 147 | } else { 148 | [myRequest setValue: @"text/xml" forHTTPHeaderField: @"Accept"]; 149 | } 150 | 151 | if (![self userAgent]) { 152 | NSString *userAgent = [[NSUserDefaults standardUserDefaults] objectForKey:@"UserAgent"]; 153 | 154 | if (userAgent) { 155 | [self setUserAgent: userAgent]; 156 | } 157 | } 158 | 159 | [myRequest setHTTPBody: content]; 160 | 161 | return (NSURLRequest *)myRequest; 162 | } 163 | 164 | #pragma mark - 165 | 166 | - (void)setValue: (NSString *)value forHTTPHeaderField: (NSString *)header { 167 | [myRequest setValue: value forHTTPHeaderField: header]; 168 | } 169 | #pragma mark - 170 | 171 | - (id) extra { 172 | return extra; 173 | } 174 | 175 | - (void) setExtra:(id) extraObject { 176 | #if ! __has_feature(objc_arc) 177 | [extra release]; 178 | extra = [extraObject retain]; 179 | #else 180 | extra = extraObject; 181 | #endif 182 | } 183 | 184 | #pragma mark - 185 | 186 | - (void)dealloc { 187 | #if ! __has_feature(objc_arc) 188 | [myRequest release]; 189 | [myXMLEncoder release]; 190 | 191 | [super dealloc]; 192 | #endif 193 | } 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class XMLRPCDecoder; 4 | 5 | @interface XMLRPCResponse : NSObject { 6 | NSString *myBody; 7 | id myObject; 8 | BOOL isFault; 9 | } 10 | 11 | - (id)initWithData: (NSData *)data; 12 | 13 | #pragma mark - 14 | 15 | - (BOOL)isFault; 16 | 17 | - (NSNumber *)faultCode; 18 | 19 | - (NSString *)faultString; 20 | 21 | #pragma mark - 22 | 23 | - (id)object; 24 | 25 | #pragma mark - 26 | 27 | - (NSString *)body; 28 | 29 | #pragma mark - 30 | 31 | - (NSString *)description; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pods/xmlrpc/XMLRPCResponse.m: -------------------------------------------------------------------------------- 1 | #import "XMLRPCResponse.h" 2 | #import "XMLRPCEventBasedParser.h" 3 | 4 | @implementation XMLRPCResponse 5 | 6 | - (id)initWithData: (NSData *)data { 7 | if (!data) { 8 | return nil; 9 | } 10 | 11 | self = [super init]; 12 | if (self) { 13 | XMLRPCEventBasedParser *parser = [[XMLRPCEventBasedParser alloc] initWithData: data]; 14 | 15 | if (!parser) { 16 | #if ! __has_feature(objc_arc) 17 | [self release]; 18 | #endif 19 | return nil; 20 | } 21 | 22 | myBody = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 23 | myObject = [parser parse]; 24 | #if ! __has_feature(objc_arc) 25 | [myObject retain]; 26 | #endif 27 | 28 | isFault = [parser isFault]; 29 | 30 | #if ! __has_feature(objc_arc) 31 | [parser release]; 32 | #endif 33 | } 34 | 35 | return self; 36 | } 37 | 38 | #pragma mark - 39 | 40 | - (BOOL)isFault { 41 | return isFault; 42 | } 43 | 44 | - (NSNumber *)faultCode { 45 | if (isFault) { 46 | return [myObject objectForKey: @"faultCode"]; 47 | } 48 | 49 | return nil; 50 | } 51 | 52 | - (NSString *)faultString { 53 | if (isFault) { 54 | return [myObject objectForKey: @"faultString"]; 55 | } 56 | 57 | return nil; 58 | } 59 | 60 | #pragma mark - 61 | 62 | - (id)object { 63 | return myObject; 64 | } 65 | 66 | #pragma mark - 67 | 68 | - (NSString *)body { 69 | return myBody; 70 | } 71 | 72 | #pragma mark - 73 | 74 | - (NSString *)description { 75 | NSMutableString *result = [NSMutableString stringWithCapacity:128]; 76 | 77 | [result appendFormat:@"[body=%@", myBody]; 78 | 79 | if (isFault) { 80 | [result appendFormat:@", fault[%@]='%@'", [self faultCode], [self faultString]]; 81 | } else { 82 | [result appendFormat:@", object=%@", myObject]; 83 | } 84 | 85 | [result appendString:@"]"]; 86 | 87 | return result; 88 | } 89 | 90 | #pragma mark - 91 | 92 | - (void)dealloc { 93 | #if ! __has_feature(objc_arc) 94 | [myBody release]; 95 | [myObject release]; 96 | 97 | [super dealloc]; 98 | #endif 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /PopoverController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverController.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 27/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class PopoverController: NSViewController { 12 | 13 | @IBOutlet weak var languageSelection: NSPopUpButton! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do view setup here. 18 | languageSelection.addItemsWithTitles((Language.getLanguages().allKeys as! [String]).sort()) 19 | 20 | let userSubtitleLanguage = NSUserDefaults.standardUserDefaults().valueForKey(Constants.Keys.subtitleLanguage) as! String 21 | 22 | let subtitleDropdownTitle = Language.getLanguages().allKeysForObject(userSubtitleLanguage)[0] as! String 23 | 24 | 25 | languageSelection.selectItemWithTitle(subtitleDropdownTitle) 26 | 27 | } 28 | 29 | let languages = Language.getLanguages() 30 | 31 | @IBAction func changeLanguage(sender: NSPopUpButton) { 32 | 33 | let selectedItem = sender.titleOfSelectedItem! 34 | 35 | NSUserDefaults.standardUserDefaults().setValue(languages[selectedItem], forKey: Constants.Keys.subtitleLanguage) 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /PopoverController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Subtitlr 2 | 3 | Subtitlr is an open source OS X app used to find and download subtitles easily. Video files are dropped into the app which then finds their hashcodes using OpenSubtitles.org algorithm and maches them against their database. Matched subtitles are downloaded in the same directory where the video files are located. 4 | 5 | ## Installation 6 | 7 | 8 | ### Prerequisites 9 | 1. XCode (can be downloaded from the app store) 10 | 2. [CocoaPods](https://cocoapods.org) 11 | 12 | ### Installation Instructions 13 | Clone the repository into a folder of your choice, and run `pod install` inside that folder. This will download the necessary dependencies and create a **Subtitlr.xcworkspace** file. 14 | 15 | Open the **Subtitlr.xcworkspace** file in XCode, go to "Product->Build" in the top bar, once this has built right-click on the "Products" folder in the left hand sidebar, and click "Open in Finder". **Subtitlr.app** will be in there, you can then drag this into your Applications folder. 16 | 17 | Alternatively, you can download Subtitlr.app in a ZIP file [here] (https://www.dropbox.com/s/et60e6lcvi3h2qc/Subtitlr.zip?dl=0). 18 | -------------------------------------------------------------------------------- /Subtitle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Subtitle.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 18/09/15. 6 | // Copyright (c) 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class Subtitle: NSObject { 13 | var path: String 14 | var ext: String 15 | var videoPath: String 16 | 17 | init(path: String, ext: String){ 18 | self.videoPath = path 19 | self.path = (path as NSString).stringByDeletingPathExtension + "." + ext 20 | self.ext = ext 21 | } 22 | } 23 | 24 | extension Subtitle: NSFilePresenter { 25 | 26 | /* 27 | Output subtitle file 28 | */ 29 | var presentedItemURL: NSURL? { 30 | let filePath = (path as NSString).stringByDeletingPathExtension + "." + ext 31 | return NSURL(fileURLWithPath: filePath) 32 | } 33 | 34 | /* 35 | "Source" file - video file which will get "modified and saved" as subtitle file 36 | */ 37 | var primaryPresentedItemURL: NSURL? { 38 | return NSURL(fileURLWithPath: videoPath) 39 | } 40 | 41 | var presentedItemOperationQueue: NSOperationQueue { 42 | return NSOperationQueue.mainQueue() 43 | } 44 | } -------------------------------------------------------------------------------- /Subtitlr 2.0/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 21/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | var mainWindowController: MainWindowController? 15 | var popoverController: PopoverController? 16 | 17 | func applicationDidFinishLaunching(aNotification: NSNotification) { 18 | 19 | let mainWindowController = MainWindowController() 20 | let popoverController = PopoverController() 21 | 22 | //put the window of the window controller on screen 23 | mainWindowController.showWindow(self) 24 | self.mainWindowController = mainWindowController 25 | self.popoverController = popoverController 26 | 27 | //check if user has selected a language, if not, set to English 28 | if NSUserDefaults.standardUserDefaults().objectForKey(Constants.Keys.subtitleLanguage) == nil { 29 | NSUserDefaults.standardUserDefaults().setObject(Constants.defaultSubtitleLanguage, forKey: Constants.Keys.subtitleLanguage) 30 | } 31 | } 32 | 33 | func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool { 34 | return true 35 | } 36 | 37 | func applicationWillTerminate(notification: NSNotification) { 38 | 39 | //save user settings before quitting 40 | NSUserDefaults.standardUserDefaults().synchronize() 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "logo_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "logo_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "logo_32-1.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "logo_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "logo_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "logo_256-1.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "logo_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "logo_512-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "logo_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "logo.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_128.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_16.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_256-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_256-1.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_256.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_32-1.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_32.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_512-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_512-1.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_512.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/Subtitlr 2.0/Assets.xcassets/AppIcon.appiconset/logo_64.png -------------------------------------------------------------------------------- /Subtitlr 2.0/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeExtensions 11 | 12 | 3g2 13 | 3gp 14 | 3gp2 15 | 3gpp 16 | 60d 17 | ajp 18 | asf 19 | asx 20 | avchd 21 | avi 22 | bik 23 | bix 24 | box 25 | cam 26 | dat 27 | divx 28 | dmf 29 | dv 30 | dvr-ms 31 | evo 32 | flc 33 | fli 34 | flic 35 | flv 36 | flx 37 | gvi 38 | gvp 39 | h264 40 | m1v 41 | m2p 42 | m2ts 43 | m2v 44 | m4e 45 | m4v 46 | mjp 47 | mjpeg 48 | mjpg 49 | mkv 50 | moov 51 | mov 52 | movhd 53 | movie 54 | movx 55 | mp4 56 | mpe 57 | mpeg 58 | mpg 59 | mpv 60 | mpv2 61 | mxf 62 | nsv 63 | nut 64 | ogg 65 | ogm 66 | omf 67 | ps 68 | qt 69 | ram 70 | rm 71 | rmvb 72 | swf 73 | ts 74 | vfw 75 | vid 76 | video 77 | viv 78 | vivo 79 | vob 80 | vro 81 | wm 82 | wmv 83 | wmx 84 | wrap 85 | wvx 86 | wx 87 | x264 88 | xvid 89 | 90 | CFBundleTypeName 91 | Video file 92 | CFBundleTypeRole 93 | Viewer 94 | 95 | 96 | CFBundleTypeExtensions 97 | 98 | sub 99 | srt 100 | txt 101 | smi 102 | ssa 103 | ass 104 | mpl 105 | 106 | CFBundleTypeName 107 | Subtitle File 108 | CFBundleTypeRole 109 | Editor 110 | NSIsRelatedItemType 111 | 112 | 113 | 114 | CFBundleExecutable 115 | $(EXECUTABLE_NAME) 116 | CFBundleIconFile 117 | 118 | CFBundleIdentifier 119 | $(PRODUCT_BUNDLE_IDENTIFIER) 120 | CFBundleInfoDictionaryVersion 121 | 6.0 122 | CFBundleName 123 | $(PRODUCT_NAME) 124 | CFBundlePackageType 125 | APPL 126 | CFBundleShortVersionString 127 | 1.0 128 | CFBundleSignature 129 | ???? 130 | CFBundleVersion 131 | 9 132 | LSApplicationCategoryType 133 | public.app-category.video 134 | LSMinimumSystemVersion 135 | $(MACOSX_DEPLOYMENT_TARGET) 136 | NSHumanReadableCopyright 137 | Copyright © 2015 Lucija Frković. All rights reserved. 138 | NSMainNibFile 139 | MainMenu 140 | NSPrincipalClass 141 | NSApplication 142 | 143 | 144 | -------------------------------------------------------------------------------- /Subtitlr 2.0/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Subtitlr 2.0Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Subtitlr 2.0Tests/OpenSubsAccessTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSubsAccessTests.swift 3 | // Subtitlr 4 | // 5 | // Created by Lucija Frković on 27/09/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Subtitlr 11 | 12 | class OpenSubsAccessTests: XCTestCase { 13 | 14 | var subsAccess = OpenSubsAccess() 15 | 16 | override func setUp() { 17 | super.setUp() 18 | subsAccess.logIn() 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | func testLogIn(){ 27 | subsAccess.logIn() 28 | XCTAssertNotNil(subsAccess.token) 29 | 30 | } 31 | 32 | func testTalkToOpenSubs(){ 33 | /* test log in */ 34 | let result = subsAccess.talkToOpenSubs("LogIn", params: ["", "", "eng", Constants.OSUserAgent]) 35 | XCTAssertNotNil(result!.valueForKey("token")) 36 | 37 | let serverInfo = subsAccess.talkToOpenSubs("ServerInfo", params: []) 38 | print(serverInfo) 39 | } 40 | 41 | func testSearchSubs(){ 42 | let file = Video(path: "/Users/spilja/Downloads/breakdance.avi") 43 | let result = subsAccess.getSubtitle(file.hash, size: Double(file.size)) 44 | XCTAssertEqual(1951887680, result!.id) 45 | XCTAssertEqual("srt", result!.format) 46 | } 47 | 48 | //TODO: add entitlements to tests?? 49 | // func testGetSubFile(){ 50 | // var file = Video(path: "/Users/spilja/Downloads/breakdance.avi", subFound: false) 51 | // subsAccess.downloadSub(1951887680, format: "srt", file: &file) 52 | // } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Subtitlr 2.0Tests/SubtitlrTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Subtitlr_2_0Tests.swift 3 | // Subtitlr 2.0Tests 4 | // 5 | // Created by Lucija Frković on 11/10/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Subtitlr 11 | 12 | class SubtitlrTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testHashMethod(){ 25 | let file = Video(path: "/Users/spilja/Downloads/breakdance.avi") 26 | XCTAssertEqual(file.hash, "8e245d9679d31e12") 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Subtitlr 2.0UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Subtitlr 2.0UITests/UITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Subtitlr_2_0UITests.swift 3 | // Subtitlr 2.0UITests 4 | // 5 | // Created by Lucija Frković on 11/10/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class Subtitlr_2_0UITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Subtitlr.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-write 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Subtitlr.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B003A1099DF698D527C753E /* libPods-Subtitlr.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 69EFDB4D604EAFD284C0AEC5 /* libPods-Subtitlr.a */; }; 11 | C60B0A491BCD41EB00DD4286 /* PopoverController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60B0A481BCD41EA00DD4286 /* PopoverController.swift */; settings = {ASSET_TAGS = (); }; }; 12 | C60B0A4B1BCD41FD00DD4286 /* PopoverController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C60B0A4A1BCD41FD00DD4286 /* PopoverController.xib */; settings = {ASSET_TAGS = (); }; }; 13 | C60B0A4E1BCE35FB00DD4286 /* dropzone_img.png in Resources */ = {isa = PBXBuildFile; fileRef = C60B0A4C1BCE35FB00DD4286 /* dropzone_img.png */; settings = {ASSET_TAGS = (); }; }; 14 | C60B0A4F1BCE35FB00DD4286 /* dropzone_img@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C60B0A4D1BCE35FB00DD4286 /* dropzone_img@2x.png */; settings = {ASSET_TAGS = (); }; }; 15 | C67C2ECD1BCA8AE100AD6F36 /* SubtitlrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67C2ECC1BCA8AE100AD6F36 /* SubtitlrTests.swift */; }; 16 | C67C2ED81BCA8AE100AD6F36 /* UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67C2ED71BCA8AE100AD6F36 /* UITests.swift */; }; 17 | C6CF29651BCA8D5800BB9B89 /* OpenSubsAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CF29641BCA8D5800BB9B89 /* OpenSubsAccess.swift */; settings = {ASSET_TAGS = (); }; }; 18 | C6CF29761BCA8E1700BB9B89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6CF29751BCA8E1700BB9B89 /* Assets.xcassets */; settings = {ASSET_TAGS = (); }; }; 19 | C6CF298D1BCA8EAD00BB9B89 /* Languages.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CF29871BCA8EAD00BB9B89 /* Languages.swift */; settings = {ASSET_TAGS = (); }; }; 20 | C6CF298E1BCA8EAD00BB9B89 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CF29881BCA8EAD00BB9B89 /* Constants.swift */; settings = {ASSET_TAGS = (); }; }; 21 | C6CF298F1BCA8EAD00BB9B89 /* Subtitlr.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = C6CF29891BCA8EAD00BB9B89 /* Subtitlr.entitlements */; settings = {ASSET_TAGS = (); }; }; 22 | C6CF29901BCA8EAD00BB9B89 /* opensubs-logo.png in Resources */ = {isa = PBXBuildFile; fileRef = C6CF298A1BCA8EAD00BB9B89 /* opensubs-logo.png */; settings = {ASSET_TAGS = (); }; }; 23 | C6CF29911BCA8EAD00BB9B89 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C6CF298B1BCA8EAD00BB9B89 /* Credits.html */; settings = {ASSET_TAGS = (); }; }; 24 | C6CF29921BCA8EAD00BB9B89 /* opensubs-logo.gif in Resources */ = {isa = PBXBuildFile; fileRef = C6CF298C1BCA8EAD00BB9B89 /* opensubs-logo.gif */; settings = {ASSET_TAGS = (); }; }; 25 | C6CF29941BCA8F9000BB9B89 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CF29931BCA8F9000BB9B89 /* AppDelegate.swift */; settings = {ASSET_TAGS = (); }; }; 26 | C6E0FC641BCA954700EC5F81 /* FileHashMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E0FC611BCA954700EC5F81 /* FileHashMethod.swift */; settings = {ASSET_TAGS = (); }; }; 27 | C6E0FC651BCA954700EC5F81 /* Subtitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E0FC621BCA954700EC5F81 /* Subtitle.swift */; settings = {ASSET_TAGS = (); }; }; 28 | C6E0FC661BCA954700EC5F81 /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E0FC631BCA954700EC5F81 /* Video.swift */; settings = {ASSET_TAGS = (); }; }; 29 | C6E0FC691BCAA52B00EC5F81 /* OpenSubsAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E0FC671BCAA4E200EC5F81 /* OpenSubsAccessTests.swift */; settings = {ASSET_TAGS = (); }; }; 30 | C6E0FC6B1BCAD5A600EC5F81 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6E0FC6A1BCAD5A600EC5F81 /* MainMenu.xib */; settings = {ASSET_TAGS = (); }; }; 31 | C6E0FC721BCAD7DC00EC5F81 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E0FC701BCAD7DC00EC5F81 /* MainWindowController.swift */; settings = {ASSET_TAGS = (); }; }; 32 | C6E0FC731BCAD7DC00EC5F81 /* MainWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6E0FC711BCAD7DC00EC5F81 /* MainWindowController.xib */; settings = {ASSET_TAGS = (); }; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | C67C2EC91BCA8AE100AD6F36 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = C67C2EAF1BCA8AE100AD6F36 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = C67C2EB61BCA8AE100AD6F36; 41 | remoteInfo = "Subtitlr 2.0"; 42 | }; 43 | C67C2ED41BCA8AE100AD6F36 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = C67C2EAF1BCA8AE100AD6F36 /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = C67C2EB61BCA8AE100AD6F36; 48 | remoteInfo = "Subtitlr 2.0"; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 69EFDB4D604EAFD284C0AEC5 /* libPods-Subtitlr.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Subtitlr.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 939DFACE05D5CB3208F84560 /* Pods-Subtitlr.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Subtitlr.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Subtitlr/Pods-Subtitlr.debug.xcconfig"; sourceTree = ""; }; 55 | C60B0A481BCD41EA00DD4286 /* PopoverController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverController.swift; sourceTree = ""; }; 56 | C60B0A4A1BCD41FD00DD4286 /* PopoverController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PopoverController.xib; sourceTree = ""; }; 57 | C60B0A4C1BCE35FB00DD4286 /* dropzone_img.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dropzone_img.png; sourceTree = ""; }; 58 | C60B0A4D1BCE35FB00DD4286 /* dropzone_img@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dropzone_img@2x.png"; sourceTree = ""; }; 59 | C622A25797A6FF275036C660 /* Pods-Subtitlr.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Subtitlr.release.xcconfig"; path = "Pods/Target Support Files/Pods-Subtitlr/Pods-Subtitlr.release.xcconfig"; sourceTree = ""; }; 60 | C67C2EB71BCA8AE100AD6F36 /* Subtitlr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Subtitlr.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | C67C2EC31BCA8AE100AD6F36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | C67C2EC81BCA8AE100AD6F36 /* Subtitlr.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Subtitlr.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | C67C2ECC1BCA8AE100AD6F36 /* SubtitlrTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubtitlrTests.swift; sourceTree = ""; }; 64 | C67C2ECE1BCA8AE100AD6F36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | C67C2ED31BCA8AE100AD6F36 /* Subtitlr.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Subtitlr.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | C67C2ED71BCA8AE100AD6F36 /* UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITests.swift; sourceTree = ""; }; 67 | C67C2ED91BCA8AE100AD6F36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | C6CF29641BCA8D5800BB9B89 /* OpenSubsAccess.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenSubsAccess.swift; sourceTree = ""; }; 69 | C6CF29751BCA8E1700BB9B89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 70 | C6CF29861BCA8EAD00BB9B89 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; 71 | C6CF29871BCA8EAD00BB9B89 /* Languages.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Languages.swift; sourceTree = ""; }; 72 | C6CF29881BCA8EAD00BB9B89 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 73 | C6CF29891BCA8EAD00BB9B89 /* Subtitlr.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Subtitlr.entitlements; sourceTree = ""; }; 74 | C6CF298A1BCA8EAD00BB9B89 /* opensubs-logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "opensubs-logo.png"; sourceTree = ""; }; 75 | C6CF298B1BCA8EAD00BB9B89 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; 76 | C6CF298C1BCA8EAD00BB9B89 /* opensubs-logo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "opensubs-logo.gif"; sourceTree = ""; }; 77 | C6CF29931BCA8F9000BB9B89 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 78 | C6E0FC611BCA954700EC5F81 /* FileHashMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHashMethod.swift; sourceTree = ""; }; 79 | C6E0FC621BCA954700EC5F81 /* Subtitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Subtitle.swift; sourceTree = ""; }; 80 | C6E0FC631BCA954700EC5F81 /* Video.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Video.swift; sourceTree = ""; }; 81 | C6E0FC671BCAA4E200EC5F81 /* OpenSubsAccessTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenSubsAccessTests.swift; sourceTree = ""; }; 82 | C6E0FC6A1BCAD5A600EC5F81 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; 83 | C6E0FC701BCAD7DC00EC5F81 /* MainWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 84 | C6E0FC711BCAD7DC00EC5F81 /* MainWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindowController.xib; sourceTree = ""; }; 85 | /* End PBXFileReference section */ 86 | 87 | /* Begin PBXFrameworksBuildPhase section */ 88 | C67C2EB41BCA8AE100AD6F36 /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | 7B003A1099DF698D527C753E /* libPods-Subtitlr.a in Frameworks */, 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | C67C2EC51BCA8AE100AD6F36 /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | ); 101 | runOnlyForDeploymentPostprocessing = 0; 102 | }; 103 | C67C2ED01BCA8AE100AD6F36 /* Frameworks */ = { 104 | isa = PBXFrameworksBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | ); 108 | runOnlyForDeploymentPostprocessing = 0; 109 | }; 110 | /* End PBXFrameworksBuildPhase section */ 111 | 112 | /* Begin PBXGroup section */ 113 | 5F0C39BF85412E4C5310E406 /* Frameworks */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 69EFDB4D604EAFD284C0AEC5 /* libPods-Subtitlr.a */, 117 | ); 118 | name = Frameworks; 119 | sourceTree = ""; 120 | }; 121 | C67C2EAE1BCA8AE100AD6F36 = { 122 | isa = PBXGroup; 123 | children = ( 124 | C6E0FC6F1BCAD77000EC5F81 /* Views */, 125 | C6E0FC6C1BCAD69100EC5F81 /* Controllers */, 126 | C6E0FC601BCA953E00EC5F81 /* Model */, 127 | C6CF29851BCA8E9F00BB9B89 /* Supporting Files */, 128 | C6CF29661BCA8D5E00BB9B89 /* API communication */, 129 | C6CF295F1BCA8D0C00BB9B89 /* UI files */, 130 | C67C2EB91BCA8AE100AD6F36 /* Subtitlr 2.0 */, 131 | C67C2ECB1BCA8AE100AD6F36 /* Tests */, 132 | C67C2ED61BCA8AE100AD6F36 /* UITests */, 133 | C67C2EB81BCA8AE100AD6F36 /* Products */, 134 | E4827C282BBCFD4CF3615B0B /* Pods */, 135 | 5F0C39BF85412E4C5310E406 /* Frameworks */, 136 | ); 137 | sourceTree = ""; 138 | }; 139 | C67C2EB81BCA8AE100AD6F36 /* Products */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | C67C2EB71BCA8AE100AD6F36 /* Subtitlr.app */, 143 | C67C2EC81BCA8AE100AD6F36 /* Subtitlr.xctest */, 144 | C67C2ED31BCA8AE100AD6F36 /* Subtitlr.xctest */, 145 | ); 146 | name = Products; 147 | sourceTree = ""; 148 | }; 149 | C67C2EB91BCA8AE100AD6F36 /* Subtitlr 2.0 */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | C6E0FC6A1BCAD5A600EC5F81 /* MainMenu.xib */, 153 | C6CF29931BCA8F9000BB9B89 /* AppDelegate.swift */, 154 | C6CF29751BCA8E1700BB9B89 /* Assets.xcassets */, 155 | C67C2EC31BCA8AE100AD6F36 /* Info.plist */, 156 | ); 157 | path = "Subtitlr 2.0"; 158 | sourceTree = ""; 159 | }; 160 | C67C2ECB1BCA8AE100AD6F36 /* Tests */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | C6E0FC671BCAA4E200EC5F81 /* OpenSubsAccessTests.swift */, 164 | C67C2ECC1BCA8AE100AD6F36 /* SubtitlrTests.swift */, 165 | C67C2ECE1BCA8AE100AD6F36 /* Info.plist */, 166 | ); 167 | name = Tests; 168 | path = "Subtitlr 2.0Tests"; 169 | sourceTree = ""; 170 | }; 171 | C67C2ED61BCA8AE100AD6F36 /* UITests */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | C67C2ED71BCA8AE100AD6F36 /* UITests.swift */, 175 | C67C2ED91BCA8AE100AD6F36 /* Info.plist */, 176 | ); 177 | name = UITests; 178 | path = "Subtitlr 2.0UITests"; 179 | sourceTree = ""; 180 | }; 181 | C6CF295F1BCA8D0C00BB9B89 /* UI files */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | C60B0A4C1BCE35FB00DD4286 /* dropzone_img.png */, 185 | C60B0A4D1BCE35FB00DD4286 /* dropzone_img@2x.png */, 186 | ); 187 | name = "UI files"; 188 | sourceTree = ""; 189 | }; 190 | C6CF29661BCA8D5E00BB9B89 /* API communication */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | C6CF29641BCA8D5800BB9B89 /* OpenSubsAccess.swift */, 194 | ); 195 | name = "API communication"; 196 | sourceTree = ""; 197 | }; 198 | C6CF29851BCA8E9F00BB9B89 /* Supporting Files */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | C6CF29861BCA8EAD00BB9B89 /* Bridging-Header.h */, 202 | C6CF29871BCA8EAD00BB9B89 /* Languages.swift */, 203 | C6CF29881BCA8EAD00BB9B89 /* Constants.swift */, 204 | C6CF29891BCA8EAD00BB9B89 /* Subtitlr.entitlements */, 205 | C6CF298A1BCA8EAD00BB9B89 /* opensubs-logo.png */, 206 | C6CF298B1BCA8EAD00BB9B89 /* Credits.html */, 207 | C6CF298C1BCA8EAD00BB9B89 /* opensubs-logo.gif */, 208 | ); 209 | name = "Supporting Files"; 210 | sourceTree = ""; 211 | }; 212 | C6E0FC601BCA953E00EC5F81 /* Model */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | C6E0FC611BCA954700EC5F81 /* FileHashMethod.swift */, 216 | C6E0FC621BCA954700EC5F81 /* Subtitle.swift */, 217 | C6E0FC631BCA954700EC5F81 /* Video.swift */, 218 | ); 219 | name = Model; 220 | sourceTree = ""; 221 | }; 222 | C6E0FC6C1BCAD69100EC5F81 /* Controllers */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | C60B0A481BCD41EA00DD4286 /* PopoverController.swift */, 226 | C6E0FC701BCAD7DC00EC5F81 /* MainWindowController.swift */, 227 | ); 228 | name = Controllers; 229 | sourceTree = ""; 230 | }; 231 | C6E0FC6F1BCAD77000EC5F81 /* Views */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | C60B0A4A1BCD41FD00DD4286 /* PopoverController.xib */, 235 | C6E0FC711BCAD7DC00EC5F81 /* MainWindowController.xib */, 236 | ); 237 | name = Views; 238 | sourceTree = ""; 239 | }; 240 | E4827C282BBCFD4CF3615B0B /* Pods */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 939DFACE05D5CB3208F84560 /* Pods-Subtitlr.debug.xcconfig */, 244 | C622A25797A6FF275036C660 /* Pods-Subtitlr.release.xcconfig */, 245 | ); 246 | name = Pods; 247 | sourceTree = ""; 248 | }; 249 | /* End PBXGroup section */ 250 | 251 | /* Begin PBXNativeTarget section */ 252 | C67C2EB61BCA8AE100AD6F36 /* Subtitlr */ = { 253 | isa = PBXNativeTarget; 254 | buildConfigurationList = C67C2EDC1BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "Subtitlr" */; 255 | buildPhases = ( 256 | DB497872C2E728CC77E482CC /* Check Pods Manifest.lock */, 257 | C67C2EB31BCA8AE100AD6F36 /* Sources */, 258 | C67C2EB41BCA8AE100AD6F36 /* Frameworks */, 259 | C67C2EB51BCA8AE100AD6F36 /* Resources */, 260 | 6B36B21AA6C21B3843E04796 /* Copy Pods Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = Subtitlr; 267 | productName = "Subtitlr 2.0"; 268 | productReference = C67C2EB71BCA8AE100AD6F36 /* Subtitlr.app */; 269 | productType = "com.apple.product-type.application"; 270 | }; 271 | C67C2EC71BCA8AE100AD6F36 /* SubtitlrTests */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = C67C2EDF1BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "SubtitlrTests" */; 274 | buildPhases = ( 275 | C67C2EC41BCA8AE100AD6F36 /* Sources */, 276 | C67C2EC51BCA8AE100AD6F36 /* Frameworks */, 277 | C67C2EC61BCA8AE100AD6F36 /* Resources */, 278 | ); 279 | buildRules = ( 280 | ); 281 | dependencies = ( 282 | C67C2ECA1BCA8AE100AD6F36 /* PBXTargetDependency */, 283 | ); 284 | name = SubtitlrTests; 285 | productName = "Subtitlr 2.0Tests"; 286 | productReference = C67C2EC81BCA8AE100AD6F36 /* Subtitlr.xctest */; 287 | productType = "com.apple.product-type.bundle.unit-test"; 288 | }; 289 | C67C2ED21BCA8AE100AD6F36 /* SubtitlrUITests */ = { 290 | isa = PBXNativeTarget; 291 | buildConfigurationList = C67C2EE21BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "SubtitlrUITests" */; 292 | buildPhases = ( 293 | C67C2ECF1BCA8AE100AD6F36 /* Sources */, 294 | C67C2ED01BCA8AE100AD6F36 /* Frameworks */, 295 | C67C2ED11BCA8AE100AD6F36 /* Resources */, 296 | ); 297 | buildRules = ( 298 | ); 299 | dependencies = ( 300 | C67C2ED51BCA8AE100AD6F36 /* PBXTargetDependency */, 301 | ); 302 | name = SubtitlrUITests; 303 | productName = "Subtitlr 2.0UITests"; 304 | productReference = C67C2ED31BCA8AE100AD6F36 /* Subtitlr.xctest */; 305 | productType = "com.apple.product-type.bundle.ui-testing"; 306 | }; 307 | /* End PBXNativeTarget section */ 308 | 309 | /* Begin PBXProject section */ 310 | C67C2EAF1BCA8AE100AD6F36 /* Project object */ = { 311 | isa = PBXProject; 312 | attributes = { 313 | LastUpgradeCheck = 0700; 314 | ORGANIZATIONNAME = "Lucija Frković"; 315 | TargetAttributes = { 316 | C67C2EB61BCA8AE100AD6F36 = { 317 | CreatedOnToolsVersion = 7.0.1; 318 | DevelopmentTeam = X4N5X87CSP; 319 | }; 320 | C67C2EC71BCA8AE100AD6F36 = { 321 | CreatedOnToolsVersion = 7.0.1; 322 | TestTargetID = C67C2EB61BCA8AE100AD6F36; 323 | }; 324 | C67C2ED21BCA8AE100AD6F36 = { 325 | CreatedOnToolsVersion = 7.0.1; 326 | TestTargetID = C67C2EB61BCA8AE100AD6F36; 327 | }; 328 | }; 329 | }; 330 | buildConfigurationList = C67C2EB21BCA8AE100AD6F36 /* Build configuration list for PBXProject "Subtitlr" */; 331 | compatibilityVersion = "Xcode 3.2"; 332 | developmentRegion = English; 333 | hasScannedForEncodings = 0; 334 | knownRegions = ( 335 | en, 336 | Base, 337 | ); 338 | mainGroup = C67C2EAE1BCA8AE100AD6F36; 339 | productRefGroup = C67C2EB81BCA8AE100AD6F36 /* Products */; 340 | projectDirPath = ""; 341 | projectRoot = ""; 342 | targets = ( 343 | C67C2EB61BCA8AE100AD6F36 /* Subtitlr */, 344 | C67C2EC71BCA8AE100AD6F36 /* SubtitlrTests */, 345 | C67C2ED21BCA8AE100AD6F36 /* SubtitlrUITests */, 346 | ); 347 | }; 348 | /* End PBXProject section */ 349 | 350 | /* Begin PBXResourcesBuildPhase section */ 351 | C67C2EB51BCA8AE100AD6F36 /* Resources */ = { 352 | isa = PBXResourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | C6CF298F1BCA8EAD00BB9B89 /* Subtitlr.entitlements in Resources */, 356 | C60B0A4F1BCE35FB00DD4286 /* dropzone_img@2x.png in Resources */, 357 | C60B0A4B1BCD41FD00DD4286 /* PopoverController.xib in Resources */, 358 | C6E0FC731BCAD7DC00EC5F81 /* MainWindowController.xib in Resources */, 359 | C60B0A4E1BCE35FB00DD4286 /* dropzone_img.png in Resources */, 360 | C6CF29921BCA8EAD00BB9B89 /* opensubs-logo.gif in Resources */, 361 | C6CF29911BCA8EAD00BB9B89 /* Credits.html in Resources */, 362 | C6CF29761BCA8E1700BB9B89 /* Assets.xcassets in Resources */, 363 | C6CF29901BCA8EAD00BB9B89 /* opensubs-logo.png in Resources */, 364 | C6E0FC6B1BCAD5A600EC5F81 /* MainMenu.xib in Resources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | C67C2EC61BCA8AE100AD6F36 /* Resources */ = { 369 | isa = PBXResourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | C67C2ED11BCA8AE100AD6F36 /* Resources */ = { 376 | isa = PBXResourcesBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXResourcesBuildPhase section */ 383 | 384 | /* Begin PBXShellScriptBuildPhase section */ 385 | 6B36B21AA6C21B3843E04796 /* Copy Pods Resources */ = { 386 | isa = PBXShellScriptBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | ); 390 | inputPaths = ( 391 | ); 392 | name = "Copy Pods Resources"; 393 | outputPaths = ( 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | shellPath = /bin/sh; 397 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Subtitlr/Pods-Subtitlr-resources.sh\"\n"; 398 | showEnvVarsInLog = 0; 399 | }; 400 | DB497872C2E728CC77E482CC /* Check Pods Manifest.lock */ = { 401 | isa = PBXShellScriptBuildPhase; 402 | buildActionMask = 2147483647; 403 | files = ( 404 | ); 405 | inputPaths = ( 406 | ); 407 | name = "Check Pods Manifest.lock"; 408 | outputPaths = ( 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | shellPath = /bin/sh; 412 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 413 | showEnvVarsInLog = 0; 414 | }; 415 | /* End PBXShellScriptBuildPhase section */ 416 | 417 | /* Begin PBXSourcesBuildPhase section */ 418 | C67C2EB31BCA8AE100AD6F36 /* Sources */ = { 419 | isa = PBXSourcesBuildPhase; 420 | buildActionMask = 2147483647; 421 | files = ( 422 | C6CF298E1BCA8EAD00BB9B89 /* Constants.swift in Sources */, 423 | C6CF29651BCA8D5800BB9B89 /* OpenSubsAccess.swift in Sources */, 424 | C6E0FC641BCA954700EC5F81 /* FileHashMethod.swift in Sources */, 425 | C6CF298D1BCA8EAD00BB9B89 /* Languages.swift in Sources */, 426 | C6CF29941BCA8F9000BB9B89 /* AppDelegate.swift in Sources */, 427 | C6E0FC661BCA954700EC5F81 /* Video.swift in Sources */, 428 | C6E0FC721BCAD7DC00EC5F81 /* MainWindowController.swift in Sources */, 429 | C60B0A491BCD41EB00DD4286 /* PopoverController.swift in Sources */, 430 | C6E0FC651BCA954700EC5F81 /* Subtitle.swift in Sources */, 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | }; 434 | C67C2EC41BCA8AE100AD6F36 /* Sources */ = { 435 | isa = PBXSourcesBuildPhase; 436 | buildActionMask = 2147483647; 437 | files = ( 438 | C6E0FC691BCAA52B00EC5F81 /* OpenSubsAccessTests.swift in Sources */, 439 | C67C2ECD1BCA8AE100AD6F36 /* SubtitlrTests.swift in Sources */, 440 | ); 441 | runOnlyForDeploymentPostprocessing = 0; 442 | }; 443 | C67C2ECF1BCA8AE100AD6F36 /* Sources */ = { 444 | isa = PBXSourcesBuildPhase; 445 | buildActionMask = 2147483647; 446 | files = ( 447 | C67C2ED81BCA8AE100AD6F36 /* UITests.swift in Sources */, 448 | ); 449 | runOnlyForDeploymentPostprocessing = 0; 450 | }; 451 | /* End PBXSourcesBuildPhase section */ 452 | 453 | /* Begin PBXTargetDependency section */ 454 | C67C2ECA1BCA8AE100AD6F36 /* PBXTargetDependency */ = { 455 | isa = PBXTargetDependency; 456 | target = C67C2EB61BCA8AE100AD6F36 /* Subtitlr */; 457 | targetProxy = C67C2EC91BCA8AE100AD6F36 /* PBXContainerItemProxy */; 458 | }; 459 | C67C2ED51BCA8AE100AD6F36 /* PBXTargetDependency */ = { 460 | isa = PBXTargetDependency; 461 | target = C67C2EB61BCA8AE100AD6F36 /* Subtitlr */; 462 | targetProxy = C67C2ED41BCA8AE100AD6F36 /* PBXContainerItemProxy */; 463 | }; 464 | /* End PBXTargetDependency section */ 465 | 466 | /* Begin XCBuildConfiguration section */ 467 | C67C2EDA1BCA8AE100AD6F36 /* Debug */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ALWAYS_SEARCH_USER_PATHS = NO; 471 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 472 | CLANG_CXX_LIBRARY = "libc++"; 473 | CLANG_ENABLE_MODULES = YES; 474 | CLANG_ENABLE_OBJC_ARC = YES; 475 | CLANG_WARN_BOOL_CONVERSION = YES; 476 | CLANG_WARN_CONSTANT_CONVERSION = YES; 477 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 478 | CLANG_WARN_EMPTY_BODY = YES; 479 | CLANG_WARN_ENUM_CONVERSION = YES; 480 | CLANG_WARN_INT_CONVERSION = YES; 481 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 482 | CLANG_WARN_UNREACHABLE_CODE = YES; 483 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 484 | CODE_SIGN_IDENTITY = "-"; 485 | COPY_PHASE_STRIP = NO; 486 | DEBUG_INFORMATION_FORMAT = dwarf; 487 | ENABLE_STRICT_OBJC_MSGSEND = YES; 488 | ENABLE_TESTABILITY = YES; 489 | GCC_C_LANGUAGE_STANDARD = gnu99; 490 | GCC_DYNAMIC_NO_PIC = NO; 491 | GCC_NO_COMMON_BLOCKS = YES; 492 | GCC_OPTIMIZATION_LEVEL = 0; 493 | GCC_PREPROCESSOR_DEFINITIONS = ( 494 | "DEBUG=1", 495 | "$(inherited)", 496 | ); 497 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 498 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 499 | GCC_WARN_UNDECLARED_SELECTOR = YES; 500 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 501 | GCC_WARN_UNUSED_FUNCTION = YES; 502 | GCC_WARN_UNUSED_VARIABLE = YES; 503 | MACOSX_DEPLOYMENT_TARGET = 10.11; 504 | MTL_ENABLE_DEBUG_INFO = YES; 505 | ONLY_ACTIVE_ARCH = YES; 506 | SDKROOT = macosx; 507 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 508 | }; 509 | name = Debug; 510 | }; 511 | C67C2EDB1BCA8AE100AD6F36 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | ALWAYS_SEARCH_USER_PATHS = NO; 515 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 516 | CLANG_CXX_LIBRARY = "libc++"; 517 | CLANG_ENABLE_MODULES = YES; 518 | CLANG_ENABLE_OBJC_ARC = YES; 519 | CLANG_WARN_BOOL_CONVERSION = YES; 520 | CLANG_WARN_CONSTANT_CONVERSION = YES; 521 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 522 | CLANG_WARN_EMPTY_BODY = YES; 523 | CLANG_WARN_ENUM_CONVERSION = YES; 524 | CLANG_WARN_INT_CONVERSION = YES; 525 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 526 | CLANG_WARN_UNREACHABLE_CODE = YES; 527 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 528 | CODE_SIGN_IDENTITY = "-"; 529 | COPY_PHASE_STRIP = NO; 530 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 531 | ENABLE_NS_ASSERTIONS = NO; 532 | ENABLE_STRICT_OBJC_MSGSEND = YES; 533 | GCC_C_LANGUAGE_STANDARD = gnu99; 534 | GCC_NO_COMMON_BLOCKS = YES; 535 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 536 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 537 | GCC_WARN_UNDECLARED_SELECTOR = YES; 538 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 539 | GCC_WARN_UNUSED_FUNCTION = YES; 540 | GCC_WARN_UNUSED_VARIABLE = YES; 541 | MACOSX_DEPLOYMENT_TARGET = 10.11; 542 | MTL_ENABLE_DEBUG_INFO = NO; 543 | SDKROOT = macosx; 544 | }; 545 | name = Release; 546 | }; 547 | C67C2EDD1BCA8AE100AD6F36 /* Debug */ = { 548 | isa = XCBuildConfiguration; 549 | baseConfigurationReference = 939DFACE05D5CB3208F84560 /* Pods-Subtitlr.debug.xcconfig */; 550 | buildSettings = { 551 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 552 | CODE_SIGN_ENTITLEMENTS = Subtitlr.entitlements; 553 | CODE_SIGN_IDENTITY = "Mac Developer"; 554 | COMBINE_HIDPI_IMAGES = YES; 555 | INFOPLIST_FILE = "Subtitlr 2.0/Info.plist"; 556 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 557 | PRODUCT_BUNDLE_IDENTIFIER = com.eagerMoose.Subtitlr; 558 | PRODUCT_NAME = Subtitlr; 559 | SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h"; 560 | }; 561 | name = Debug; 562 | }; 563 | C67C2EDE1BCA8AE100AD6F36 /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | baseConfigurationReference = C622A25797A6FF275036C660 /* Pods-Subtitlr.release.xcconfig */; 566 | buildSettings = { 567 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 568 | CODE_SIGN_ENTITLEMENTS = Subtitlr.entitlements; 569 | CODE_SIGN_IDENTITY = "Mac Developer"; 570 | COMBINE_HIDPI_IMAGES = YES; 571 | INFOPLIST_FILE = "Subtitlr 2.0/Info.plist"; 572 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 573 | PRODUCT_BUNDLE_IDENTIFIER = com.eagerMoose.Subtitlr; 574 | PRODUCT_NAME = Subtitlr; 575 | SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h"; 576 | }; 577 | name = Release; 578 | }; 579 | C67C2EE01BCA8AE100AD6F36 /* Debug */ = { 580 | isa = XCBuildConfiguration; 581 | buildSettings = { 582 | BUNDLE_LOADER = "$(TEST_HOST)"; 583 | CODE_SIGN_ENTITLEMENTS = Subtitlr.entitlements; 584 | COMBINE_HIDPI_IMAGES = YES; 585 | INFOPLIST_FILE = "Subtitlr 2.0Tests/Info.plist"; 586 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 587 | PODS_ROOT = "${SRCROOT}/Pods"; 588 | PRODUCT_BUNDLE_IDENTIFIER = "com.eagerMoose.Subtitlr-2-0Tests"; 589 | PRODUCT_NAME = Subtitlr; 590 | SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h"; 591 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Subtitlr.app/Contents/MacOS/Subtitlr"; 592 | USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/Headers/Public\" \"${PODS_ROOT}/Headers/Public/GZIP\" \"${PODS_ROOT}/Headers/Public/NSData+Base64\" \"${PODS_ROOT}/Headers/Public/xmlrpc\""; 593 | }; 594 | name = Debug; 595 | }; 596 | C67C2EE11BCA8AE100AD6F36 /* Release */ = { 597 | isa = XCBuildConfiguration; 598 | buildSettings = { 599 | BUNDLE_LOADER = "$(TEST_HOST)"; 600 | CODE_SIGN_ENTITLEMENTS = Subtitlr.entitlements; 601 | COMBINE_HIDPI_IMAGES = YES; 602 | INFOPLIST_FILE = "Subtitlr 2.0Tests/Info.plist"; 603 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 604 | PODS_ROOT = "${SRCROOT}/Pods"; 605 | PRODUCT_BUNDLE_IDENTIFIER = "com.eagerMoose.Subtitlr-2-0Tests"; 606 | PRODUCT_NAME = Subtitlr; 607 | SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h"; 608 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Subtitlr.app/Contents/MacOS/Subtitlr"; 609 | USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/Headers/Public\" \"${PODS_ROOT}/Headers/Public/GZIP\" \"${PODS_ROOT}/Headers/Public/NSData+Base64\" \"${PODS_ROOT}/Headers/Public/xmlrpc\""; 610 | }; 611 | name = Release; 612 | }; 613 | C67C2EE31BCA8AE100AD6F36 /* Debug */ = { 614 | isa = XCBuildConfiguration; 615 | buildSettings = { 616 | COMBINE_HIDPI_IMAGES = YES; 617 | INFOPLIST_FILE = "Subtitlr 2.0UITests/Info.plist"; 618 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 619 | PRODUCT_BUNDLE_IDENTIFIER = "com.eagerMoose.Subtitlr-2-0UITests"; 620 | PRODUCT_NAME = Subtitlr; 621 | TEST_TARGET_NAME = "Subtitlr 2.0"; 622 | USES_XCTRUNNER = YES; 623 | }; 624 | name = Debug; 625 | }; 626 | C67C2EE41BCA8AE100AD6F36 /* Release */ = { 627 | isa = XCBuildConfiguration; 628 | buildSettings = { 629 | COMBINE_HIDPI_IMAGES = YES; 630 | INFOPLIST_FILE = "Subtitlr 2.0UITests/Info.plist"; 631 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 632 | PRODUCT_BUNDLE_IDENTIFIER = "com.eagerMoose.Subtitlr-2-0UITests"; 633 | PRODUCT_NAME = Subtitlr; 634 | TEST_TARGET_NAME = "Subtitlr 2.0"; 635 | USES_XCTRUNNER = YES; 636 | }; 637 | name = Release; 638 | }; 639 | /* End XCBuildConfiguration section */ 640 | 641 | /* Begin XCConfigurationList section */ 642 | C67C2EB21BCA8AE100AD6F36 /* Build configuration list for PBXProject "Subtitlr" */ = { 643 | isa = XCConfigurationList; 644 | buildConfigurations = ( 645 | C67C2EDA1BCA8AE100AD6F36 /* Debug */, 646 | C67C2EDB1BCA8AE100AD6F36 /* Release */, 647 | ); 648 | defaultConfigurationIsVisible = 0; 649 | defaultConfigurationName = Release; 650 | }; 651 | C67C2EDC1BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "Subtitlr" */ = { 652 | isa = XCConfigurationList; 653 | buildConfigurations = ( 654 | C67C2EDD1BCA8AE100AD6F36 /* Debug */, 655 | C67C2EDE1BCA8AE100AD6F36 /* Release */, 656 | ); 657 | defaultConfigurationIsVisible = 0; 658 | defaultConfigurationName = Release; 659 | }; 660 | C67C2EDF1BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "SubtitlrTests" */ = { 661 | isa = XCConfigurationList; 662 | buildConfigurations = ( 663 | C67C2EE01BCA8AE100AD6F36 /* Debug */, 664 | C67C2EE11BCA8AE100AD6F36 /* Release */, 665 | ); 666 | defaultConfigurationIsVisible = 0; 667 | defaultConfigurationName = Release; 668 | }; 669 | C67C2EE21BCA8AE100AD6F36 /* Build configuration list for PBXNativeTarget "SubtitlrUITests" */ = { 670 | isa = XCConfigurationList; 671 | buildConfigurations = ( 672 | C67C2EE31BCA8AE100AD6F36 /* Debug */, 673 | C67C2EE41BCA8AE100AD6F36 /* Release */, 674 | ); 675 | defaultConfigurationIsVisible = 0; 676 | defaultConfigurationName = Release; 677 | }; 678 | /* End XCConfigurationList section */ 679 | }; 680 | rootObject = C67C2EAF1BCA8AE100AD6F36 /* Project object */; 681 | } 682 | -------------------------------------------------------------------------------- /Subtitlr.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Subtitlr.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/Subtitlr 2.0.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Subtitlr.xcodeproj/xcuserdata/spilja.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Subtitlr 2.0.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C67C2EB61BCA8AE100AD6F36 16 | 17 | primary 18 | 19 | 20 | C67C2EC71BCA8AE100AD6F36 21 | 22 | primary 23 | 24 | 25 | C67C2ED21BCA8AE100AD6F36 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Video.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Videos.swift 3 | // subs 4 | // 5 | // Created by Lucija Frković on 21/07/15. 6 | // Copyright © 2015 Lucija Frković. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | 13 | class Video { 14 | init(path: String){ 15 | self.path = path 16 | self.subStatus = SubtitleStauts.NotSearched 17 | } 18 | 19 | var path: String 20 | 21 | enum SubtitleStauts { 22 | case NotSearched 23 | case Found 24 | case NotFound 25 | } 26 | 27 | var subStatus: SubtitleStauts? 28 | 29 | var subtitle: Subtitle? 30 | 31 | var hash: String { 32 | get { 33 | return FileHash().stringForHash(FileHash().hashForPath(path).fileHash) as String 34 | } 35 | } 36 | 37 | var size: UInt64 { 38 | get { 39 | return FileHash().hashForPath(path).fileSize 40 | } 41 | } 42 | 43 | 44 | var fileName: String { 45 | get { 46 | return (path as NSString).lastPathComponent 47 | } 48 | } 49 | 50 | func downloadSubtitle(){ 51 | let osApi = OpenSubsAccess() 52 | osApi.logIn() 53 | 54 | if let result = osApi.getSubtitle(self.hash, size: Double(self.size)){ 55 | let subFile = osApi.downloadSub(result.id, format: result.format) 56 | 57 | subtitle = Subtitle(path: path, ext: result.format) 58 | NSFileCoordinator.addFilePresenter(subtitle!) 59 | 60 | if let fData = subtitle, let url = fData.presentedItemURL { 61 | var errorMain: NSError? 62 | let coord = NSFileCoordinator(filePresenter: fData) 63 | coord.coordinateWritingItemAtURL(url, options: NSFileCoordinatorWritingOptions(), error: &errorMain, byAccessor: { writeUrl in 64 | subFile!.writeToFile(self.subtitle!.path, atomically: true) 65 | 66 | if NSFileManager.defaultManager().fileExistsAtPath(self.subtitle!.path) { 67 | self.subStatus = SubtitleStauts.Found 68 | } 69 | return 70 | }) 71 | } 72 | } 73 | else { 74 | subStatus = SubtitleStauts.NotFound 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /dropzone_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/dropzone_img.png -------------------------------------------------------------------------------- /dropzone_img@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/dropzone_img@2x.png -------------------------------------------------------------------------------- /opensubs-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/opensubs-logo.gif -------------------------------------------------------------------------------- /opensubs-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucijafrkovic/Subtitlr/0c0327bcdad6a317734952a0d410c43c045a69db/opensubs-logo.png --------------------------------------------------------------------------------