@capgo/capacitor-video-thumbnails 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapgoCapacitorVideoThumbnails.podspec +17 -0
- package/LICENSE +373 -0
- package/Package.swift +28 -0
- package/README.md +125 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/app/capgo/capacitor/videothumbnails/CapgoVideoThumbnailsPlugin.java +148 -0
- package/dist/docs.json +182 -0
- package/dist/esm/definitions.d.ts +89 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +8 -0
- package/dist/esm/web.js +46 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +60 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +63 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CapgoVideoThumbnailsPlugin/CapgoVideoThumbnailsPlugin.swift +131 -0
- package/ios/Tests/CapgoVideoThumbnailsPluginTests/CapgoVideoThumbnailsPluginTests.swift +11 -0
- package/package.json +89 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import AVFoundation
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Please read the Capacitor iOS Plugin Development Guide
|
|
8
|
+
* here: https://capacitorjs.com/docs/plugins/ios
|
|
9
|
+
*/
|
|
10
|
+
@objc(CapgoVideoThumbnailsPlugin)
|
|
11
|
+
public class CapgoVideoThumbnailsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
12
|
+
private let pluginVersion: String = "8.0.0"
|
|
13
|
+
public let identifier = "CapgoVideoThumbnailsPlugin"
|
|
14
|
+
public let jsName = "CapgoVideoThumbnails"
|
|
15
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
16
|
+
CAPPluginMethod(name: "getThumbnail", returnType: CAPPluginReturnPromise),
|
|
17
|
+
CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
@objc func getThumbnail(_ call: CAPPluginCall) {
|
|
21
|
+
guard let sourceUri = call.getString("sourceUri") else {
|
|
22
|
+
call.reject("sourceUri is required")
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let time = call.getDouble("time") ?? 0
|
|
27
|
+
let quality = call.getDouble("quality") ?? 1.0
|
|
28
|
+
let headers = call.getObject("headers") as? [String: String]
|
|
29
|
+
|
|
30
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
31
|
+
self.generateThumbnail(sourceUri: sourceUri, time: time, quality: quality, headers: headers) { result in
|
|
32
|
+
switch result {
|
|
33
|
+
case .success(let thumbnailResult):
|
|
34
|
+
call.resolve(thumbnailResult)
|
|
35
|
+
case .failure(let error):
|
|
36
|
+
call.reject(error.localizedDescription)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private func generateThumbnail(
|
|
43
|
+
sourceUri: String,
|
|
44
|
+
time: Double,
|
|
45
|
+
quality: Double,
|
|
46
|
+
headers: [String: String]?,
|
|
47
|
+
completion: @escaping (Result<[String: Any], Error>) -> Void
|
|
48
|
+
) {
|
|
49
|
+
var asset: AVAsset
|
|
50
|
+
|
|
51
|
+
if sourceUri.hasPrefix("http://") || sourceUri.hasPrefix("https://") {
|
|
52
|
+
guard let url = URL(string: sourceUri) else {
|
|
53
|
+
completion(.failure(NSError(domain: "CapgoVideoThumbnails", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(sourceUri)"])))
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if let headers = headers, !headers.isEmpty {
|
|
58
|
+
var urlRequest = URLRequest(url: url)
|
|
59
|
+
for (key, value) in headers {
|
|
60
|
+
urlRequest.setValue(value, forHTTPHeaderField: key)
|
|
61
|
+
}
|
|
62
|
+
asset = AVURLAsset(url: url, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
|
|
63
|
+
} else {
|
|
64
|
+
asset = AVURLAsset(url: url)
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
// Handle local file paths
|
|
68
|
+
var fileUrl: URL
|
|
69
|
+
if sourceUri.hasPrefix("file://") {
|
|
70
|
+
guard let url = URL(string: sourceUri) else {
|
|
71
|
+
completion(.failure(NSError(domain: "CapgoVideoThumbnails", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid file URL: \(sourceUri)"])))
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
fileUrl = url
|
|
75
|
+
} else {
|
|
76
|
+
fileUrl = URL(fileURLWithPath: sourceUri)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
guard FileManager.default.fileExists(atPath: fileUrl.path) else {
|
|
80
|
+
completion(.failure(NSError(domain: "CapgoVideoThumbnails", code: 2, userInfo: [NSLocalizedDescriptionKey: "File does not exist: \(sourceUri)"])))
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
asset = AVURLAsset(url: fileUrl)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let imageGenerator = AVAssetImageGenerator(asset: asset)
|
|
88
|
+
imageGenerator.appliesPreferredTrackTransform = true
|
|
89
|
+
imageGenerator.requestedTimeToleranceAfter = .zero
|
|
90
|
+
imageGenerator.requestedTimeToleranceBefore = .zero
|
|
91
|
+
|
|
92
|
+
// Convert milliseconds to CMTime
|
|
93
|
+
let timeInSeconds = time / 1000.0
|
|
94
|
+
let cmTime = CMTime(seconds: timeInSeconds, preferredTimescale: 600)
|
|
95
|
+
|
|
96
|
+
do {
|
|
97
|
+
let cgImage = try imageGenerator.copyCGImage(at: cmTime, actualTime: nil)
|
|
98
|
+
let uiImage = UIImage(cgImage: cgImage)
|
|
99
|
+
|
|
100
|
+
// Save to temporary file
|
|
101
|
+
guard let imageData = uiImage.jpegData(compressionQuality: CGFloat(quality)) else {
|
|
102
|
+
completion(.failure(NSError(domain: "CapgoVideoThumbnails", code: 3, userInfo: [NSLocalizedDescriptionKey: "Failed to convert image to JPEG"])))
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let tempDir = FileManager.default.temporaryDirectory
|
|
107
|
+
let fileName = "thumbnail_\(UUID().uuidString).jpg"
|
|
108
|
+
let fileUrl = tempDir.appendingPathComponent(fileName)
|
|
109
|
+
|
|
110
|
+
try imageData.write(to: fileUrl)
|
|
111
|
+
|
|
112
|
+
let result: [String: Any] = [
|
|
113
|
+
"uri": fileUrl.absoluteString,
|
|
114
|
+
"width": cgImage.width,
|
|
115
|
+
"height": cgImage.height
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
DispatchQueue.main.async {
|
|
119
|
+
completion(.success(result))
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
DispatchQueue.main.async {
|
|
123
|
+
completion(.failure(NSError(domain: "CapgoVideoThumbnails", code: 4, userInfo: [NSLocalizedDescriptionKey: "Failed to generate thumbnail: \(error.localizedDescription)"])))
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
129
|
+
call.resolve(["version": self.pluginVersion])
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import CapgoVideoThumbnailsPlugin
|
|
3
|
+
|
|
4
|
+
class CapgoVideoThumbnailsTests: XCTestCase {
|
|
5
|
+
func testPluginVersion() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
let plugin = CapgoVideoThumbnailsPlugin()
|
|
9
|
+
XCTAssertNotNil(plugin)
|
|
10
|
+
}
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capgo/capacitor-video-thumbnails",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Generate video thumbnails from local or remote video files",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
16
|
+
"CapgoCapacitorVideoThumbnails.podspec"
|
|
17
|
+
],
|
|
18
|
+
"author": "Martin Donadieu <martin@capgo.app>",
|
|
19
|
+
"license": "MPL-2.0",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Cap-go/capacitor-video-thumbnails.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/Cap-go/capacitor-video-thumbnails/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://capgo.app/docs/plugins/video-thumbnails/",
|
|
28
|
+
"keywords": [
|
|
29
|
+
"capacitor",
|
|
30
|
+
"plugin",
|
|
31
|
+
"native",
|
|
32
|
+
"video",
|
|
33
|
+
"thumbnails",
|
|
34
|
+
"thumbnail",
|
|
35
|
+
"frame",
|
|
36
|
+
"extract"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
40
|
+
"verify:ios": "xcodebuild -scheme CapgoCapacitorVideoThumbnails -destination generic/platform=iOS",
|
|
41
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
42
|
+
"verify:web": "npm run build",
|
|
43
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
44
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
45
|
+
"eslint": "eslint . --ext ts",
|
|
46
|
+
"prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
47
|
+
"swiftlint": "node-swiftlint",
|
|
48
|
+
"docgen": "docgen --api CapgoVideoThumbnailsPlugin --output-readme README.md --output-json dist/docs.json",
|
|
49
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
50
|
+
"clean": "rimraf ./dist",
|
|
51
|
+
"watch": "tsc --watch",
|
|
52
|
+
"prepublishOnly": "npm run build"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@capacitor/android": "^8.0.0",
|
|
56
|
+
"@capacitor/core": "^8.0.0",
|
|
57
|
+
"@capacitor/docgen": "^0.3.1",
|
|
58
|
+
"@capacitor/ios": "^8.0.0",
|
|
59
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
60
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
61
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
62
|
+
"@types/node": "^24.10.1",
|
|
63
|
+
"eslint": "^8.57.1",
|
|
64
|
+
"eslint-plugin-import": "^2.31.0",
|
|
65
|
+
"prettier": "^3.6.2",
|
|
66
|
+
"prettier-plugin-java": "^2.7.7",
|
|
67
|
+
"rimraf": "^6.1.0",
|
|
68
|
+
"rollup": "^4.53.2",
|
|
69
|
+
"swiftlint": "^2.0.0",
|
|
70
|
+
"typescript": "^5.9.3",
|
|
71
|
+
"prettier-pretty-check": "^0.2.0"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@capacitor/core": ">=8.0.0"
|
|
75
|
+
},
|
|
76
|
+
"prettier": "@ionic/prettier-config",
|
|
77
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
78
|
+
"eslintConfig": {
|
|
79
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
80
|
+
},
|
|
81
|
+
"capacitor": {
|
|
82
|
+
"ios": {
|
|
83
|
+
"src": "ios"
|
|
84
|
+
},
|
|
85
|
+
"android": {
|
|
86
|
+
"src": "android"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|