forked from Ivasoft/mattermost-mobile
Generate video thumb from file url instead of public url (#6922)
This commit is contained in:
@@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -20,8 +21,12 @@ import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
import com.mattermost.helpers.Credentials;
|
||||
import com.reactlibrary.createthumbnail.CreateThumbnailModule;
|
||||
import com.mattermost.helpers.RealPathUtil;
|
||||
|
||||
import java.io.File;
|
||||
@@ -29,6 +34,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class MattermostManagedModule extends ReactContextBaseJavaModule {
|
||||
@@ -206,6 +212,30 @@ public class MattermostManagedModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createThumbnail(ReadableMap options, Promise promise) {
|
||||
try {
|
||||
WritableMap optionsMap = Arguments.createMap();
|
||||
optionsMap.merge(options);
|
||||
String url = options.hasKey("url") ? options.getString("url") : "";
|
||||
URL videoUrl = new URL(url);
|
||||
String serverUrl = videoUrl.getProtocol() + "://" + videoUrl.getHost() + ":" + videoUrl.getPort();
|
||||
String token = Credentials.getCredentialsForServerSync(this.reactContext, serverUrl);
|
||||
if (!TextUtils.isEmpty(token)) {
|
||||
WritableMap headers = Arguments.createMap();
|
||||
if (optionsMap.hasKey("headers")) {
|
||||
headers.merge(optionsMap.getMap("headers"));
|
||||
}
|
||||
headers.putString("Authorization", "Bearer " + token);
|
||||
optionsMap.putMap("headers", headers);
|
||||
}
|
||||
CreateThumbnailModule thumb = new CreateThumbnailModule(this.reactContext);
|
||||
thumb.create(optionsMap.copy(), promise);
|
||||
} catch (Exception e) {
|
||||
promise.reject("CreateThumbnail_ERROR", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SaveDataTask extends GuardedResultAsyncTask<Object> {
|
||||
private final WeakReference<Context> weakContext;
|
||||
private final String fromFile;
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
||||
import {StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||
import {createThumbnail} from 'react-native-create-thumbnail';
|
||||
import {StyleSheet, useWindowDimensions, View, NativeModules} from 'react-native';
|
||||
|
||||
import {updateLocalFile} from '@actions/local/file';
|
||||
import {buildFilePreviewUrl, fetchPublicLink} from '@actions/remote/file';
|
||||
import {buildFilePreviewUrl, buildFileUrl} from '@actions/remote/file';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import ProgressiveImage from '@components/progressive_image';
|
||||
import {useServerUrl} from '@context/server';
|
||||
@@ -18,6 +17,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import FileIcon from './file_icon';
|
||||
|
||||
import type {ResizeMode} from 'react-native-fast-image';
|
||||
const {createThumbnail} = NativeModules.MattermostManaged;
|
||||
|
||||
type Props = {
|
||||
index: number;
|
||||
@@ -84,11 +84,9 @@ const VideoFile = ({
|
||||
try {
|
||||
const exists = data.mini_preview ? await fileExists(data.mini_preview) : false;
|
||||
if (!data.mini_preview || !exists) {
|
||||
// We use the public link to avoid having to pass the token through a third party
|
||||
// library
|
||||
const publicUri = await fetchPublicLink(serverUrl, data.id!);
|
||||
if (('link') in publicUri) {
|
||||
const {path: uri, height, width} = await createThumbnail({url: data.localPath || publicUri.link, timeStamp: 2000});
|
||||
const videoUrl = buildFileUrl(serverUrl, data.id!);
|
||||
if (videoUrl) {
|
||||
const {path: uri, height, width} = await createThumbnail({url: data.localPath || videoUrl, timeStamp: 2000});
|
||||
data.mini_preview = uri;
|
||||
data.height = height;
|
||||
data.width = width;
|
||||
|
||||
@@ -27,4 +27,12 @@ import Gekidou
|
||||
@objc func setPreference(_ value: Any?, forKey name: String) {
|
||||
Preferences.default.set(value, forKey: name)
|
||||
}
|
||||
|
||||
@objc func getToken(for url: String) -> String? {
|
||||
if let token = try? Keychain.default.getToken(for: url) {
|
||||
return token
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "MattermostManaged.h"
|
||||
#import "CreateThumbnail.h"
|
||||
#import "Mattermost-Swift.h"
|
||||
|
||||
@implementation MattermostManaged
|
||||
|
||||
@@ -107,7 +109,6 @@ RCT_EXPORT_METHOD(renameDatabase: (NSString *)databaseName to: (NSString *) new
|
||||
NSDictionary *appGroupDir = [self appGroupSharedDirectory];
|
||||
NSString *databaseDir;
|
||||
NSString *newDBDir;
|
||||
|
||||
|
||||
if(databaseName){
|
||||
databaseDir = [NSString stringWithFormat:@"%@/%@%@", appGroupDir[@"databasePath"], databaseName , @".db"];
|
||||
@@ -200,4 +201,27 @@ RCT_EXPORT_METHOD(lockPortrait)
|
||||
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(createThumbnail:(NSDictionary *)config findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
NSMutableDictionary *newConfig = [config mutableCopy];
|
||||
NSMutableDictionary *headers = [config[@"headers"] ?: @{} mutableCopy];
|
||||
NSString *url = (NSString *)[config objectForKey:@"url"] ?: @"";
|
||||
NSURL *vidURL = nil;
|
||||
NSString *url_ = [url lowercaseString];
|
||||
|
||||
if ([url_ hasPrefix:@"http://"] || [url_ hasPrefix:@"https://"] || [url_ hasPrefix:@"file://"]) {
|
||||
vidURL = [NSURL URLWithString:url];
|
||||
NSString *serverUrl = [NSString stringWithFormat:@"%@://%@:%@", vidURL.scheme, vidURL.host, vidURL.port];
|
||||
if (vidURL != nil) {
|
||||
NSString *token = [[GekidouWrapper default] getTokenFor:serverUrl];
|
||||
if (token != nil) {
|
||||
|
||||
headers[@"Authorization"] = [NSString stringWithFormat:@"Bearer %@", token];
|
||||
newConfig[@"headers"] = headers;
|
||||
}
|
||||
}
|
||||
}
|
||||
[CreateThumbnail create:newConfig findEventsWithResolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
53
patches/react-native-create-thumbnail+1.6.4.patch
Normal file
53
patches/react-native-create-thumbnail+1.6.4.patch
Normal file
@@ -0,0 +1,53 @@
|
||||
diff --git a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h
|
||||
index 28b1d9b..cb63c52 100644
|
||||
--- a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h
|
||||
+++ b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h
|
||||
@@ -3,5 +3,5 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface CreateThumbnail : NSObject <RCTBridgeModule>
|
||||
-
|
||||
++(void)create:(NSDictionary *)config findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
|
||||
@end
|
||||
diff --git a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m
|
||||
index 92cc49f..23cc83c 100644
|
||||
--- a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m
|
||||
+++ b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m
|
||||
@@ -6,6 +6,10 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
RCT_EXPORT_METHOD(create:(NSDictionary *)config findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
+ [CreateThumbnail create:config findEventsWithResolver:resolve rejecter:reject];
|
||||
+}
|
||||
+
|
||||
++(void) create:(NSDictionary *)config findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
||||
NSString *url = (NSString *)[config objectForKey:@"url"] ?: @"";
|
||||
int timeStamp = [[config objectForKey:@"timeStamp"] intValue] ?: 0;
|
||||
NSString *format = (NSString *)[config objectForKey:@"format"] ?: @"jpeg";
|
||||
@@ -82,7 +86,7 @@ RCT_EXPORT_METHOD(create:(NSDictionary *)config findEventsWithResolver:(RCTPromi
|
||||
}
|
||||
}
|
||||
|
||||
-- (unsigned long long) sizeOfFolderAtPath:(NSString *)path {
|
||||
++ (unsigned long long) sizeOfFolderAtPath:(NSString *)path {
|
||||
NSArray *files = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:path error:nil];
|
||||
NSEnumerator *enumerator = [files objectEnumerator];
|
||||
NSString *fileName;
|
||||
@@ -93,7 +97,7 @@ RCT_EXPORT_METHOD(create:(NSDictionary *)config findEventsWithResolver:(RCTPromi
|
||||
return size;
|
||||
}
|
||||
|
||||
-- (void) cleanDir:(NSString *)path forSpace:(unsigned long long)size {
|
||||
++ (void) cleanDir:(NSString *)path forSpace:(unsigned long long)size {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSError *error = nil;
|
||||
unsigned long long deletedSize = 0;
|
||||
@@ -110,7 +114,7 @@ RCT_EXPORT_METHOD(create:(NSDictionary *)config findEventsWithResolver:(RCTPromi
|
||||
return;
|
||||
}
|
||||
|
||||
-- (void) generateThumbImage:(AVURLAsset *)asset atTime:(int)timeStamp completion:(void (^)(UIImage* thumbnail))completion failure:(void (^)(NSError* error))failure {
|
||||
++ (void) generateThumbImage:(AVURLAsset *)asset atTime:(int)timeStamp completion:(void (^)(UIImage* thumbnail))completion failure:(void (^)(NSError* error))failure {
|
||||
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
|
||||
generator.appliesPreferredTrackTransform = YES;
|
||||
generator.maximumSize = CGSizeMake(512, 512);
|
||||
Reference in New Issue
Block a user