Skip to content

Commit

Permalink
HTMLパースめっちゃ早くなった〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 今夜は祭りじゃ
Browse files Browse the repository at this point in the history
  • Loading branch information
rinsuki committed Sep 20, 2018
1 parent b6ff729 commit 661d06a
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 34 deletions.
1 change: 1 addition & 0 deletions Podfile
Expand Up @@ -9,6 +9,7 @@ def based_pods
pod 'XCGLogger', '~> 6.0.2'
pod 'SDWebImage', '~> 4.0'
pod 'Kanna', '~> 4.0.0'
pod 'Fuzi', '~> 2.1.0'
end

target 'iMast' do
Expand Down
10 changes: 7 additions & 3 deletions Podfile.lock
Expand Up @@ -3,9 +3,10 @@ PODS:
- Alamofire (4.7.3)
- Compass (6.0.0)
- Eureka (4.1.1)
- Fuzi (2.1.0)
- GRDB.swift (3.2.0)
- HydraAsync (1.2.1)
- Kanna (4.0.0)
- Kanna (4.0.1)
- KeychainAccess (3.1.1)
- Notifwift (1.0.0)
- ObjcExceptionBridging (1.0.1):
Expand All @@ -28,6 +29,7 @@ DEPENDENCIES:
- Alamofire (~> 4.5)
- Compass
- Eureka (~> 4.1.0)
- Fuzi (~> 2.1.0)
- GRDB.swift
- HydraAsync
- Kanna (~> 4.0.0)
Expand All @@ -46,6 +48,7 @@ SPEC REPOS:
- Alamofire
- Compass
- Eureka
- Fuzi
- GRDB.swift
- HydraAsync
- Kanna
Expand All @@ -64,9 +67,10 @@ SPEC CHECKSUMS:
Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568
Compass: ff30e2056c549ea5cb5b8a307d28ef628e4209ff
Eureka: b88fb930e42c79f8c03c373d0fcdc28c1d6c50ed
Fuzi: 8c57344debff6d3a0c76a9e0f549152defdaaa48
GRDB.swift: c5bb04b25a9931fec937920e913787e45f96124f
HydraAsync: 8f2ab62d57e140b4ca587ae0f66e1eb04e8e6965
Kanna: d5ae2a26472f7e7a474e7f36a9cd8aa2c8c63ad3
Kanna: 15569a2331b79782a1753cf280c8e69e2a033654
KeychainAccess: 7bd430028059754a3debab3cfc0bd1fc7fb85df3
Notifwift: 1c5d63660ac2cad79870b2eb759d6c8a3e600343
ObjcExceptionBridging: c30e00eb3700467e695faeea30e26e18bd445001
Expand All @@ -77,6 +81,6 @@ SPEC CHECKSUMS:
SwiftyJSON: c29297daf073d2aa016295d5809cdd68045c39b3
XCGLogger: 4fc1bc0bdd5828cb8dc8da7a843536cda1bea8f3

PODFILE CHECKSUM: 9d08dacfaad16798d4f7fce77710fb5fa3b3a3bd
PODFILE CHECKSUM: 134d9d8206be51b032e776ff8087146402c97a9f

COCOAPODS: 1.5.3
10 changes: 8 additions & 2 deletions iMast.xcodeproj/project.pbxproj
Expand Up @@ -107,6 +107,7 @@
CE7B144A212EB959004904BA /* DispatchQueue+mainSafeSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7B1444212EB8F1004904BA /* DispatchQueue+mainSafeSync.swift */; };
CE8209982150EC390064FC93 /* OtherMenuPushSettingsGroupNotifyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8209972150EC390064FC93 /* OtherMenuPushSettingsGroupNotifyTableViewController.swift */; };
CE84AB19209526C500A3C4D2 /* NSFWGuardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE84AB18209526C500A3C4D2 /* NSFWGuardView.swift */; };
CE8C713B2153323D00D53BCF /* String+parseText2HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8C713A2153323D00D53BCF /* String+parseText2HTML.swift */; };
CE8DF1851FED41C4005278FE /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = CE8DF1841FED41C4005278FE /* Podfile */; };
CE8E8E661F172A770007A311 /* MastodonPostDetail.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE8E8E651F172A770007A311 /* MastodonPostDetail.storyboard */; };
CE8E8E681F18714D0007A311 /* MastodonPostDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8E8E671F18714D0007A311 /* MastodonPostDetailTableViewController.swift */; };
Expand Down Expand Up @@ -312,6 +313,7 @@
CE7B1444212EB8F1004904BA /* DispatchQueue+mainSafeSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+mainSafeSync.swift"; sourceTree = "<group>"; };
CE8209972150EC390064FC93 /* OtherMenuPushSettingsGroupNotifyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherMenuPushSettingsGroupNotifyTableViewController.swift; sourceTree = "<group>"; };
CE84AB18209526C500A3C4D2 /* NSFWGuardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSFWGuardView.swift; sourceTree = "<group>"; };
CE8C713A2153323D00D53BCF /* String+parseText2HTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+parseText2HTML.swift"; sourceTree = "<group>"; };
CE8DF1841FED41C4005278FE /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Podfile; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
CE8E8E651F172A770007A311 /* MastodonPostDetail.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MastodonPostDetail.storyboard; sourceTree = "<group>"; };
CE8E8E671F18714D0007A311 /* MastodonPostDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonPostDetailTableViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -545,6 +547,7 @@
children = (
CE2D2AED210C5668003B92B8 /* Notification.Name.swift */,
CE2D2B0121105DC2003B92B8 /* Hydra.Promise+wrapper.swift */,
CE8C713A2153323D00D53BCF /* String+parseText2HTML.swift */,
CE2D2B062110686A003B92B8 /* UNUserNotificationCenter.requestAuthorization+Hydra.Promise.swift */,
CEC6BBF92104FA1B003ECE10 /* SVProgressHUD+Hydra.swift */,
CEC6BC0E21076DB3003ECE10 /* String+emojify.swift */,
Expand Down Expand Up @@ -1089,6 +1092,7 @@
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/Compass/Compass.framework",
"${BUILT_PRODUCTS_DIR}/Eureka/Eureka.framework",
"${BUILT_PRODUCTS_DIR}/Fuzi/Fuzi.framework",
"${BUILT_PRODUCTS_DIR}/GRDB.swift/GRDB.framework",
"${BUILT_PRODUCTS_DIR}/HydraAsync/Hydra.framework",
"${BUILT_PRODUCTS_DIR}/Kanna/Kanna.framework",
Expand All @@ -1108,6 +1112,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Compass.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Eureka.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Fuzi.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Hydra.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kanna.framework",
Expand Down Expand Up @@ -1154,6 +1159,7 @@
CE54BC7720E041A50034B63E /* UserProfileInfoTableViewCell.swift in Sources */,
CE9B1AA41F9DEDB50044341A /* ProfileCardViewController.swift in Sources */,
CE3DFEE01FEE4C51005A480D /* UserDefaultsDict.swift in Sources */,
CE8C713B2153323D00D53BCF /* String+parseText2HTML.swift in Sources */,
2A66E7FA1EAEB0DD00735081 /* GoodUtils.swift in Sources */,
CEE2542E2004FA76005FEB6F /* MastodonNotification.swift in Sources */,
CE1002C820065DA30041B636 /* MastodonSearchResult.swift in Sources */,
Expand Down Expand Up @@ -1484,7 +1490,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 4XKKKM86RN;
HEADER_SEARCH_PATHS = "";
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
INFOPLIST_FILE = iMast/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand All @@ -1510,7 +1516,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 4XKKKM86RN;
HEADER_SEARCH_PATHS = "";
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
INFOPLIST_FILE = iMast/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand Down
5 changes: 5 additions & 0 deletions iMast/OtherMenu/OtherMenuSettingsTableViewController.swift
Expand Up @@ -218,6 +218,11 @@ class OtherMenuSettingsTableViewController: FormViewController {
})
}
}
self.form +++ Section("実験的な要素")
<<< SwitchRow() { row in
row.title = "新しいHTMLパーサーを使う"
row.userDefaultsConnect(.newHtmlParser)
}
self.title = "設定"
let callhelpitem = UIBarButtonItem(title: "ヘルプ", style: .plain) { _ in
let safari = SFSafariViewController(url: URL(string: "https://cinderella-project.github.io/iMast/help/settings.html")!)
Expand Down
29 changes: 29 additions & 0 deletions iMast/Settings.bundle/Acknowledgements.plist
Expand Up @@ -136,6 +136,35 @@ SOFTWARE.
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2015 Ce Zheng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>Fuzi</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (C) 2018 Gwendal Roué
Expand Down
117 changes: 117 additions & 0 deletions iMast/SharedSources/Extensions/String+parseText2HTML.swift
@@ -0,0 +1,117 @@
//
// String+parseText2HTML.swift
// iMast
//
// Created by user on 2018/09/20.
// Copyright © 2018年 rinsuki. All rights reserved.
//

import Foundation
import Fuzi

extension String {
func parseText2HTMLNew() -> NSAttributedString? {
do {
let document = try Fuzi.HTMLDocument(string: self)
guard let root = document.root?.children(staticTag: "body").first else {
print("empty root")
return NSAttributedString(string: "")
}

let fetchNodeTypes: [Fuzi.XMLNodeType] = [
.Text,
.Element
]

func generateAttrStr(nodes: [XMLNode]) -> NSMutableAttributedString {
let attrStr = NSMutableAttributedString(string: "")
for node in nodes {
switch(node.type) {
case .Text:
attrStr.append(NSAttributedString(string: node.stringValue))
case .Element:
if let element = node.toElement() {
var childAttrStr = generateAttrStr(nodes: element.childNodes(ofTypes: fetchNodeTypes))
if let tagName = element.tag?.lowercased() {
switch tagName {
case "br":
childAttrStr.append(NSAttributedString(string: "\n"))
case "p":
childAttrStr.append(NSAttributedString(string: "\n\n"))
case "a":
if let href = element.attributes["href"] {
childAttrStr.addAttributes([
.link: href,
.underlineStyle: NSUnderlineStyle.styleSingle.rawValue,
], range: NSRange(location: 0, length: childAttrStr.length))
}
case "img":
if let src = element.attributes["src"], let srcUrl = URL(string: src),
let srcData = try? Data(contentsOf: srcUrl) {
let attachment = NSTextAttachment()
attachment.image = UIImage(data: srcData)
attachment.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
childAttrStr = NSMutableAttributedString(attachment: attachment)
}
default:
break
}
}
attrStr.append(childAttrStr)
}
default:
print("unknown node.type", node.type)
}
}
return attrStr
}

let attrStr = generateAttrStr(nodes: root.childNodes(ofTypes: fetchNodeTypes))
var count = 0
for char in attrStr.string.reversed() {
if char == "\n" {
count += 1
} else {
break
}
}
attrStr.deleteCharacters(in: NSRange(location: attrStr.length - count, length: count))
return attrStr
} catch let error {
print("failed to parse in new parser", error)
return nil
}
}

func parseText2HTML() -> NSAttributedString? {
if Defaults[.newHtmlParser], let newParserResult = self.parseText2HTMLNew() {
return newParserResult
}
if !self.replace("<p>","").replace("</p>","").contains("<") {
return nil
}
if html2ascacheavail[self] ?? false {
return html2ascache[self] ?? nil
}

// 受け取ったデータをUTF-8エンコードする
let encodeData = self.data(using: String.Encoding.utf8, allowLossyConversion: true)

// 表示データのオプションを設定する
let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [
NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue
]

// 文字列の変換処理
var attributedString:NSAttributedString?
attributedString = try? NSAttributedString(
data: encodeData!,
options: attributedOptions,
documentAttributes: nil
)
html2ascache[self] = attributedString

return attributedString
}
}
31 changes: 2 additions & 29 deletions iMast/SharedSources/GoodUtils.swift
Expand Up @@ -200,35 +200,6 @@ extension String {
return self.replacingOccurrences(of: target, with: to)
}

func parseText2HTML() -> NSAttributedString? {
if !self.replace("<p>","").replace("</p>","").contains("<") {
return nil
}
if html2ascacheavail[self] ?? false {
return html2ascache[self] ?? nil
}

// 受け取ったデータをUTF-8エンコードする
let encodeData = self.data(using: String.Encoding.utf8, allowLossyConversion: true)

// 表示データのオプションを設定する
let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [
NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue
]

// 文字列の変換処理
var attributedString:NSAttributedString?
attributedString = try? NSAttributedString(
data: encodeData!,
options: attributedOptions,
documentAttributes: nil
)
html2ascache[self] = attributedString

return attributedString
}

func format(_ params: CVarArg...) -> String{
return String(format: self, arguments: params)
}
Expand Down Expand Up @@ -350,6 +321,8 @@ extension DefaultsKeys {
static let groupNotifyTypeMention = DefaultsKey<Bool>("group_notify_type_mention", default: false)
static let groupNotifyTypeFollow = DefaultsKey<Bool>("group_notify_type_follow", default: false)
static let groupNotifyTypeUnknown = DefaultsKey<Bool>("group_notify_type_unknown", default: false)

static let newHtmlParser = DefaultsKey<Bool>("new_html_parser", default: false)
}

let jsISODateDecoder = JSONDecoder.DateDecodingStrategy.custom {
Expand Down

0 comments on commit 661d06a

Please sign in to comment.