globular-mvc
Version:
Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)
1,199 lines (1,000 loc) • 305 kB
JavaScript
import '@polymer/iron-icons/iron-icons.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-input/paper-input.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-checkbox/paper-checkbox.js';
import '@polymer/iron-icons/editor-icons.js'
import "@polymer/iron-icons/social-icons";
import "@polymer/iron-icons/av-icons";
import "@polymer/iron-icons/maps-icons";
import "@polymer/paper-progress/paper-progress.js"
import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js'
import '@polymer/paper-listbox/paper-listbox.js'
import '@polymer/paper-item/paper-item.js'
import "./DiskSpace.js"
import "./Share.js"
import * as getUuid from 'uuid-by-string'
import { generatePeerToken, getUrl, Model } from '../Model';
import { File as File__ } from "../File"; // File object already exist in js and I need to use it...
import { Menu } from './Menu';
import { PermissionsManager } from './Permissions';
import { FileMetaDataInfo, InformationsManager } from './Informations'
import { playVideo, playVideos } from './Video'
import { playAudio, playAudios } from './Audio'
import { GlobularFileReader } from './Reader'
import { v4 as uuidv4 } from "uuid";
// Menu to set action on files.
import { DropdownMenu } from './dropdownMenu.js';
import { AddPublicDirRequest, ConvertVideoToHlsRequest, ConvertVideoToMpeg4H264Request, CopyRequest, CreateDirRequest, CreateLnkRequest, CreateVideoPreviewRequest, CreateVideoTimeLineRequest, DeleteDirRequest, DeleteFileRequest, GetFileInfoRequest, GetPublicDirsRequest, MoveRequest, ReadFileRequest, RemovePublicDirRequest, SaveFileRequest, StartProcessAudioRequest, StartProcessVideoRequest, UploadFileRequest, UploadVideoRequest } from 'globular-web-client/file/file_pb';
import { createArchive, deleteDir, deleteFile, downloadFileHttp, renameFile, uploadFiles } from 'globular-web-client/api';
import { ApplicationView } from '../ApplicationView';
import { Application } from '../Application';
import { GetSharedResourceRqst, SubjectType } from 'globular-web-client/rbac/rbac_pb';
import { fireResize, getCoords, randomUUID } from './utility';
import * as getUuidByString from 'uuid-by-string';
import { ImageViewer } from './Image';
import { AssociateFileWithTitleRequest, CreateTitleRequest, CreateVideoRequest, GetFileAudiosRequest, GetFileTitlesRequest, GetFileVideosRequest, Person, Poster, Title, Video, Publisher, CreatePersonRequest, GetTitleByIdRequest } from 'globular-web-client/title/title_pb';
import { DownloadTorrentRequest, DropTorrentRequest, GetTorrentInfosRequest, GetTorrentLnksRequest } from 'globular-web-client/torrent/torrent_pb';
import { getImdbInfo } from './Search';
import { setMoveable } from './moveable'
import { setResizeable } from './rezieable'
import { SplitView } from './Splitter'
import { Account } from '../Account';
import { mergeTypedArrays, uint8arrayToStringMethod } from "../Utility";
import { ShareResourceMenu } from './Share.js';
import "../style.css"
// keep track of shared directory
var shared = {}
var public_ = {}
/**
* Format file size from bytes to Gb, Mb or Kb...
* @param {*} f_size
* @returns
*/
export function getFileSizeString(f_size) {
// In case of already converted values...
if (typeof f_size === 'string' || f_size instanceof String) {
return f_size
}
let size = ""
if (f_size > 1024) {
if (f_size > 1024 * 1024) {
if (f_size > 1024 * 1024 * 1024) {
let fileSize = f_size / (1024 * 1024 * 1024);
size = fileSize.toFixed(2) + " GB";
} else {
let fileSize = f_size / (1024 * 1024);
size = fileSize.toFixed(2) + " MB";
}
} else {
let fileSize = f_size / 1024;
size = fileSize.toFixed(2) + " KB";
}
} else {
size = f_size + " bytes";
}
return size
}
// Return the size of a file at url.
function getFileSize(url_, callback, errorcallback) {
let url = window.location.protocol + "//" + window.location.host + "/file_size"
var xmlhttp = new XMLHttpRequest();
xmlhttp.timeout = 10 * 1000
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && (this.status == 201 || this.status == 200)) {
let obj = JSON.parse(this.responseText)
callback(obj.size);
} else if (this.readyState == 4) {
errorcallback("fail to get the configuration file at url " + url + " status " + this.status)
}
};
url += "?url=" + url_
xmlhttp.open("GET", url, true);
xmlhttp.setRequestHeader("domain", Model.domain);
xmlhttp.send();
}
function copyToClipboard(text) {
var dummy = document.createElement("textarea");
// to avoid breaking orgain page when copying more words
// cant copy when adding below this code
// dummy.style.display = 'none'
document.body.appendChild(dummy);
//Be careful if you use texarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard
dummy.value = text;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}
// Now I will test if imdb info are allready asscociated.
export function getTitleInfo(file, callback) {
let globules = Model.getGlobules()
globules = globules.filter(function (e) { return e.domain !== file.globule.domain })
globules.unshift(file.globule)
if (file.titles) {
if (file.titles.length > 0) {
callback(file.titles)
return
}
}
// Now I will get titles info.
let ___getTitleInfo___ = (index) => {
let g = globules[index]
index++
__getTitleInfo__(g, file, (_titles_) => {
if (_titles_.length > 0) {
_titles_.forEach(t => t.globule = g)
if (!file.titles) {
file.titles = []
}
file.titles = file.titles.concat(_titles_)
callback(file.titles)
return
}
if (index < globules.length) {
___getTitleInfo___(index)
} else {
if (file.titles) {
callback(file.titles)
} else {
callback([])
}
}
})
}
let index = 0
___getTitleInfo___(index)
}
function __getTitleInfo__(globule, file, callback) {
let rqst = new GetFileTitlesRequest
rqst.setIndexpath(globule.config.DataPath + "/search/titles")
rqst.setFilepath(file.path)
generatePeerToken(globule, token => {
globule.titleService.getFileTitles(rqst, { application: Application.application, domain: globule.domain, token: token })
.then(rsp => {
callback(rsp.getTitles().getTitlesList())
})
.catch(err => {
// so here no title was found...
callback([])
})
})
}
export function getVideoInfo(file, callback) {
if (file.videos) {
if (file.videos.length > 0) {
callback(file.videos)
return
}
}
let globules = Model.getGlobules()
globules = globules.filter(function (e) { return e.domain !== file.globule.domain })
globules.unshift(file.globule)
// Now I will get titles info.
let ___getVideoInfo___ = (index) => {
let g = globules[index]
index++
__getVideoInfo__(g, file, (_videos_) => {
if (_videos_.length > 0) {
_videos_.forEach(v => v.globule = g)
if (!file.videos) {
file.videos = []
}
file.videos = file.videos.concat(_videos_)
callback(file.videos)
return
}
if (index < globules.length) {
___getVideoInfo___(index)
} else {
if (file.videos) {
callback(file.videos)
} else {
callback([])
}
}
})
}
let index = 0
___getVideoInfo___(index)
}
function __getVideoInfo__(globule, file, callback) {
let rqst = new GetFileVideosRequest
rqst.setIndexpath(globule.config.DataPath + "/search/videos")
rqst.setFilepath(file.path)
generatePeerToken(globule, token => {
globule.titleService.getFileVideos(rqst, { application: Application.application, domain: globule.domain, token: token })
.then(rsp => {
let videos = rsp.getVideos().getVideosList()
callback(videos)
})
.catch(err => {
callback([])
})
})
}
export function getAudioInfo(file, callback) {
let globules = Model.getGlobules()
globules = globules.filter(function (e) { return e.domain !== file.globule.domain })
globules.unshift(file.globule)
if (file.audios) {
if (file.audios.length > 0) {
callback(file.audios)
return
}
}
// Now I will get titles info.
let ___getAudioInfo___ = (index) => {
let g = globules[index]
index++
__getAudioInfo__(g, file, (_audios_) => {
if (_audios_.length > 0) {
_audios_.forEach(a => a.globule = g)
if (!file.audios) {
file.audios = []
}
file.audios = file.audios.concat(_audios_)
callback(file.audios)
return
}
if (index < globules.length) {
___getAudioInfo___(index)
} else {
if (file.audios) {
callback(file.audios)
} else {
callback([])
}
}
})
}
let index = 0
___getAudioInfo___(index)
}
function __getAudioInfo__(globule, file, callback) {
let rqst = new GetFileAudiosRequest
rqst.setIndexpath(globule.config.DataPath + "/search/audios")
rqst.setFilepath(file.path)
generatePeerToken(globule, token => {
globule.titleService.getFileAudios(rqst, { application: Application.application, domain: globule.domain, token: token })
.then(rsp => {
let audios = rsp.getAudios().getAudiosList()
// set the globule.
audios.forEach(a => a.globule = globule)
callback(audios)
})
.catch(err => {
callback([])
})
})
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
function markAsShare(dir) {
shared[dir.path] = {};
dir._files.forEach(f => {
if (f._isDir) {
markAsShare(f)
}
})
}
function markAsPublic(dir, parent) {
public_[dir.path] = {};
dir.__parent__ = parent // keep track of the original directory on the disck
dir._files.forEach(f => {
if (f._isDir) {
markAsPublic(f, parent)
}
})
}
function getElementIndex(element) {
return Array.from(element.parentNode.children).indexOf(element);
}
// so here I will initialyse lnk's in that directory
function initLnks(dir, callback) {
// callback(dir)
let initLink_ = (index) => {
if (index == dir.files.length) {
callback(dir)
return
}
let f = dir.files[index]
index += 1
if (!f.isDir) {
if (f.name.endsWith(".lnk")) {
File__.readText(f,
txt => {
f.lnk = File__.fromString(txt)
initLink_(index)
},
() => {
initLink_(index)
})
} else {
initLink_(index)
}
} else {
initLink_(index)
}
}
let index = 0;
initLink_(index)
}
export function getImage(callback, images, files, index, globule) {
let f = files[index];
index++
// set the url for the image.
let url = ""
if (!globule) {
// Here I will use the default globule...
url = window.location.protocol + "//" + window.location.hostname + ":"
if (Application.globular.config.Protocol == "https") {
url += Application.globular.config.PortHttps
} else {
url += Application.globular.config.PortHttp
}
} else {
// Get image from the globule.
url = globule.config.Protocol + "://" + globule.domain
if (globule.config.Protocol == "https") {
if (globule.config.PortHttps != 443)
url += ":" + globule.config.PortHttps
} else {
if (globule.config.PortHttps != 80)
url += ":" + globule.config.PortHttp
}
}
if (f == undefined) {
callback([])
return
}
if (!f.path) {
callback([])
return
}
let path = f.path.split("/")
path.forEach(item => {
item = item.trim()
if (item.length > 0)
url += "/" + encodeURIComponent(item)
})
generatePeerToken(globule, token => {
// Set url query parameter.
url += "?domain=" + globule.domain
url += "&application=" + Model.application
url += "&token=" + token
var xhr = new XMLHttpRequest();
xhr.timeout = 10 * 1000
xhr.open('GET', url, true);
xhr.setRequestHeader("token", token);
xhr.setRequestHeader("application", Model.application);
xhr.setRequestHeader("domain", globule.domain);
// Set responseType to 'arraybuffer', we want raw binary data buffer
xhr.responseType = 'blob';
xhr.onload = (rsp) => {
if (rsp.currentTarget.status == 200) {
var reader = new FileReader();
reader.readAsDataURL(rsp.currentTarget.response);
reader.onload = function (e) {
let img = document.createElement("img")
img.src = e.target.result
images.push(img)
if (index < files.length) {
getImage(callback, images, files, index, globule)
} else if (callback != undefined) {
callback(images)
}
};
}
};
xhr.send();
})
}
// Keep dir info in map to save time...
let dirs = {}
// Usefull to get dir like /shared or /public that dosent exist on the server.
export function getLocalDir(globule, path) {
// replace separator...
path = path.split("\\").join("/")
let key = getUuidByString(globule.domain + "@" + path)
let dir = dirs[key]
if (dir != null) {
return dir
}
return null
}
/**
* Read dir from local map if available. Read from the server
* if not in the map of force (in case of refresh)
* @param {*} path The path of the dir on the server
* @param {*} callback The success callback
* @param {*} errorCallback The error callback
* @param {*} force If set the dir will be read from the server.
*/
function _readDir(path, callback, errorCallback, globule, force = false) {
// replace separator...
path = path.split("\\").join("/")
let key = getUuidByString(globule.domain + "@" + path)
if (!force || path == "/public" || path == "/shared") {
let dir = dirs[key]
if (dir != null) {
if (dir.files.length > 0) {
callback(dirs[key])
return
}
}
}
// Here I will keep the dir info in the cache...
File__.readDir(path, false, (dir) => {
initLnks(dir, dir => {
callback(dir)
})
// replace separator...
dir.path = dir.path.split("\\").join("/")
let parent = dir.path.substring(0, dir.path.lastIndexOf("/"))
if (public_[parent]) {
markAsPublic(dir, parent)
}
dirs[key] = dir
}, errorCallback, globule)
}
function getHiddenFiles(path, callback, globule) {
let thumbnailPath = path.replace("/playlist.m3u8", "")
if (thumbnailPath.lastIndexOf(".mp3") != -1 || thumbnailPath.lastIndexOf(".mp4") != -1 || thumbnailPath.lastIndexOf(".mkv") != -1 || thumbnailPath.lastIndexOf(".avi") != -1 || thumbnailPath.lastIndexOf(".MP4") != -1 || thumbnailPath.lastIndexOf(".MKV") != -1 || thumbnailPath.lastIndexOf(".AVI") != -1) {
thumbnailPath = thumbnailPath.substring(0, thumbnailPath.lastIndexOf("."))
}
thumbnailPath = thumbnailPath.substring(0, thumbnailPath.lastIndexOf("/") + 1) + ".hidden" + thumbnailPath.substring(thumbnailPath.lastIndexOf("/")) + "/__preview__"
_readDir(thumbnailPath, callback, err => { console.log(err); callback(null); }, globule)
}
function _publishSetDirEvent(path, file_explorer_) {
file_explorer_.displayWaitMessage("load " + path)
_readDir(path, (dir) => {
Model.eventHub.publish("__set_dir_event__", { dir: dir, file_explorer_id: file_explorer_.id }, true)
file_explorer_.resume()
}, err => { ApplicationView.displayMessage(err, 3000); file_explorer_.resume(); }, file_explorer_.globule)
}
// the paper tray
var paperTray = [];
var editMode = "";
/**
* That class is the base class of FilesListView and FilesIconView
*/
export class FilesView extends HTMLElement {
constructor() {
super()
// must icon or list view one is active at time.
this._active_ = false
// The parent file explorer
this._file_explorer_ = null;
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
// The active explorer path.
this.path = undefined
// The current directory.
this.__dir__ = null;
// The list of files to delete
this.selected = {};
// The function will be call in case of error.
this.onerror = err => ApplicationView.displayMessage(err, 3000);
// Innitialisation of the layout.
let id = "_" + uuidv4().split("-").join("_").split("@").join("_");
// Create the share resource menu.
this.shareResource = new ShareResourceMenu
let menuItemsHTML = `
<globular-dropdown-menu-item id="file-infos-menu-item" icon="icons:info" text="File Infos" action=""> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="title-infos-menu-item" icon="icons:info" text="Title Infos" action="" style="display: none;"> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="manage-acess-menu-item" icon="folder-shared" text="Manage access" action=""></globular-dropdown-menu-item>
<globular-dropdown-menu-item id="refresh-infos-menu-item" icon="icons:refresh" text="Refresh infos" action="" style="display: none;"></globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="video-menu-item" icon="maps:local-movies" text="Movies" action="" style="display: none;">
<globular-dropdown-menu>
<globular-dropdown-menu-item id="generate-timeline-menu-item" icon="maps:local-movies" text="generate timeline" action=""> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="generate-preview-menu-item" icon="maps:local-movies" text="generate preview" action=""> </globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="to-mp4-menu-item" icon="maps:local-movies" text="convert to mp4" action="" style="display: none;"> </globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="to-hls-menu-item" icon="maps:local-movies" text="convert to hls" action="" style="display: none;"> </globular-dropdown-menu-item>
</globular-dropdown-menu>
</globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="cut-menu-item" icon="icons:content-cut" text="Cut" action=""></globular-dropdown-menu-item>
<globular-dropdown-menu-item id="copy-menu-item" icon="content-copy" text="Copy" action=""></globular-dropdown-menu-item>
<globular-dropdown-menu-item id="paste-menu-item" icon="icons:content-paste" action="" text="Paste"></globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="rename-menu-item" text="Rename" icon="icons:create" action=""> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="delete-menu-item" icon="icons:delete" action="" text="Delete"> </globular-dropdown-menu-item>
<globular-dropdown-menu-item separator="true" id="download-menu-item" icon="icons:cloud-download" text="Download" action=""> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="open-in-new-tab-menu-item" icon="icons:open-in-new" text="Open in new tab" action="" style="display: none;"> </globular-dropdown-menu-item>
<globular-dropdown-menu-item id="copy-url-menu-item" icon="icons:link" text="Copy url" action=""> </globular-dropdown-menu-item>
`
this.menu = new DropdownMenu("icons:more-vert")
this.menu.className = "file-dropdown-menu"
this.menu.innerHTML = menuItemsHTML
this.videMenuItem = this.menu.querySelector("#video-menu-item")
this.fileInfosMenuItem = this.menu.querySelector("#file-infos-menu-item")
this.titleInfosMenuItem = this.menu.querySelector("#title-infos-menu-item")
this.refreshInfoMenuItem = this.menu.querySelector("#refresh-infos-menu-item")
this.mananageAccessMenuItem = this.menu.querySelector("#manage-acess-menu-item")
this.renameMenuItem = this.menu.querySelector("#rename-menu-item")
this.deleteMenuItem = this.menu.querySelector("#delete-menu-item")
this.downloadMenuItem = this.menu.querySelector("#download-menu-item")
this.openInNewTabItem = this.menu.querySelector("#open-in-new-tab-menu-item")
this.copyUrlItem = this.menu.querySelector("#copy-url-menu-item")
// video conversion menu
this.generateTimeLineItem = this.menu.querySelector("#generate-timeline-menu-item")
this.generatePreviewItem = this.menu.querySelector("#generate-preview-menu-item")
this.toMp4MenuItem = this.menu.querySelector("#to-mp4-menu-item")
this.toHlsMenuItem = this.menu.querySelector("#to-hls-menu-item")
// Now the cut copy and paste menu...
this.cutMenuItem = this.menu.querySelector("#cut-menu-item")
this.copyMenuItem = this.menu.querySelector("#copy-menu-item")
this.pasteMenuItem = this.menu.querySelector("#paste-menu-item")
// Action to do when file is set
this.menu.setFile = (f) => {
this.menu.file = f;
if (this.menu.file.mime.startsWith("video") || this.menu.file.videos != undefined || this.menu.file.titles != undefined || this.menu.file.isDir) {
this.titleInfosMenuItem.style.display = "block"
if (this.menu.file.mime.startsWith("video")) {
this.videMenuItem.style.display = "block"
this.openInNewTabItem.style.display = "block"
this.generateTimeLineItem.style.display = "block"
this.generatePreviewItem.style.display = "block"
if (this.menu.file.name.endsWith(".mp4") || this.menu.file.name.endsWith(".MP4")) {
this.toHlsMenuItem.style.display = "block"
this.toMp4MenuItem.style.display = "none"
} else if (this.menu.file.mime == "video/hls-stream") {
this.toHlsMenuItem.style.display = "none"
this.toMp4MenuItem.style.display = "none"
} else {
this.toHlsMenuItem.style.display = "none"
this.toMp4MenuItem.style.display = "block"
}
}
} else {
this.videMenuItem.style.display = "none"
if (this.menu.file.mime.startsWith("audio")) {
this.titleInfosMenuItem.style.display = "block"
} else {
this.titleInfosMenuItem.style.display = "none"
}
if (this.menu.file.isDir) {
this.refreshInfoMenuItem.style.display = "block"
this.videMenuItem.style.display = "block"
this.toHlsMenuItem.style.display = "block"
this.toMp4MenuItem.style.display = "block"
this.generateTimeLineItem.style.display = "none"
this.generatePreviewItem.style.display = "none"
}
this.openInNewTabItem.style.display = "none"
}
}
this.refreshInfoMenuItem.action = () => {
let rqst = new StartProcessVideoRequest
rqst.setPath(this.menu.file.path)
let globule = this._file_explorer_.globule
generatePeerToken(globule, token => {
globule.fileService.startProcessVideo(rqst, { application: Application.application, domain: globule.domain, token: token }).then(() => {
ApplicationView.displayMessage("informations are now updated", 3000)
})
.catch(err => ApplicationView.displayMessage(err, 3000))
})
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.cutMenuItem.action = () => {
editMode = "cut"
paperTray = [];
for (var key in this.selected) {
paperTray.push(this.selected[key].path)
}
// Append file to file menu
if (paperTray.length == 0) {
paperTray.push(this.menu.file.path)
}
// empty the selection.
this.selected = {}
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.copyMenuItem.action = () => {
// So here I will display choice to the user and set the edit mode penpending it response.
paperTray = [];
for (var key in this.selected) {
paperTray.push(this.selected[key].path)
}
// Append file to file menu
if (paperTray.length == 0) {
paperTray.push(this.menu.file.path)
}
// empty the selection.
this.selected = {}
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.pasteMenuItem.action = () => {
paperTray = [];
if (editMode == "copy") {
// Here I will call move on the file manager
this.copy(this.menu.file.path)
} else if (editMode == "cut") {
// Here I will call copy
this.move(this.menu.file.path)
}
// empty the selection.
this.selected = {}
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.openInNewTabItem.action = () => {
let globule = this._file_explorer_.globule
generatePeerToken(globule, token => {
let url = getUrl(globule)
this.menu.file.path.split("/").forEach(item => {
let component = encodeURIComponent(item.trim())
if (component.length > 0) {
url += "/" + component
}
})
if (this.menu.file.mime == "video/hls-stream") {
url += "/playlist.m3u8"
}
url += "?application=" + Model.application;
url += "&token=" + token
window.open(url, '_blank', "fullscreen=yes");
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
})
}
this.copyUrlItem.action = () => {
let globule = this._file_explorer_.globule
generatePeerToken(globule, token => {
let url = getUrl(globule)
this.menu.file.path.split("/").forEach(item => {
let component = encodeURIComponent(item.trim())
if (component.length > 0) {
url += "/" + component
}
})
if (this.menu.file.mime == "video/hls-stream") {
url += "/playlist.m3u8"
}
url += "?application=" + Model.application;
url += "&token=" + token
copyToClipboard(url)
ApplicationView.displayMessage("url was copy to clipboard...", 3000)
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
})
}
this.downloadMenuItem.action = () => {
// Here I will create an archive from the selected files and dowload it...
let files = [];
let globule = null;
for (var key in this.selected) {
files.push(this.selected[key].path)
globule = this.selected[key].globule
}
if (files.length > 0) {
generatePeerToken(globule, token => {
// Create a tempory name...
let uuid = "_" + uuidv4().split("-").join("_").split("@").join("_");
this._file_explorer_.displayWaitMessage("create archive before for selected files...")
createArchive(globule, files, uuid,
path => {
let url = getUrl(globule)
path.split("/").forEach(item => {
item = item.trim()
if (item.length > 0) {
url += "/" + encodeURIComponent(item)
}
})
url += "?application=" + Model.application
if (token) {
url += "&token=" + token
}
// Download the file...
this._file_explorer_.displayWaitMessage("start download archive " + path)
console.log(url)
downloadFileHttp(url, uuid + ".tar.gz",
() => {
// Now I will remove the file from the server....
this._file_explorer_.displayWaitMessage("remove archive " + path)
deleteFile(globule, path,
() => {
this._file_explorer_.resume()
},
err => { ApplicationView.displayMessage(err, 3000); this._file_explorer_.resume() }, token)
}, token)
}, err => { ApplicationView.displayMessage(err, 3000); this._file_explorer_.resume() }, token)
})
} else {
let path = this.menu.file.path
let name = path.substring(path.lastIndexOf("/") + 1)
let globule = this.menu.file.globule
// if the file is a directory I will create archive and download it.
if (this.menu.file.isDir) {
generatePeerToken(globule, token => {
this._file_explorer_.displayWaitMessage("create archive before for " + this.menu.file.path)
createArchive(globule, [path], name,
path_ => {
let url = getUrl(globule)
path_.split("/").forEach(item => {
item = item.trim()
if (item.length > 0) {
url += "/" + encodeURIComponent(item)
}
})
url += "?application=" + Model.application
if (token) {
url += "&token=" + token
}
// Download the file...
this._file_explorer_.displayWaitMessage("start download " + name + ".tar.gz")
downloadFileHttp(url, name + ".tar.gz",
() => {
// Now I will remove the file from the server....
deleteFile(globule, path_,
() => {
this._file_explorer_.resume()
this.selected = {} // clear up selected files.
},
err => { ApplicationView.displayMessage(err, 3000); this._file_explorer_.resume(); this.selected = {} }, token)
}, token)
}, err => { ApplicationView.displayMessage(err, 3000); this._file_explorer_.resume(); this.selected = {} }, token)
})
} else {
// simply download the file.
generatePeerToken(globule, token => {
let url = getUrl(globule)
path.split("/").forEach(item => {
item = item.trim()
if (item.length > 0) {
url += "/" + encodeURIComponent(item)
}
})
url += "?application=" + Model.application
if (token) {
url += "&token=" + token
}
downloadFileHttp(url, name,
() => {
// Now I will remove the file from the server....
this.selected = {}
}, token), err => { ApplicationView.displayMessage(err, 3000); this.selected = {} }
})
}
}
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.deleteMenuItem.action = () => {
let files = []
let fileList = ""
for (var fileName in this.selected) {
let file = this.selected[fileName]
if (file.lnk) {
if (!file.name.endsWith(".lnk")) {
file = file.lnk // here I will delete the lnk and not the original file.
}
}
fileList += `<div>${file.path}</div>`
files.push(file)
}
// if not checked but selected with menu...
if (fileList.length == 0) {
let file = this.menu.file
if (file.lnk) {
if (!file.name.endsWith(".lnk")) {
file = file.lnk // here I will delete the lnk and not the original file.
}
}
fileList += `<div>${file.path}</div>`
files.push(file)
}
let toast = ApplicationView.displayMessage(
`
<style>
#yes-no-files-delete-box{
display: flex;
flex-direction: column;
}
#yes-no-files-delete-box globular-files-card{
padding-bottom: 10px;
}
#yes-no-files-delete-box div{
display: flex;
padding-bottom: 10px;
}
</style>
<div id="yes-no-files-delete-box">
<div>Your about to delete files</div>
<div style="display: flex; flex-direction: column;">
${fileList}
</div>
<div>Is it what you want to do? </div>
<div style="justify-content: flex-end;">
<paper-button raised id="yes-delete-files">Yes</paper-button>
<paper-button raised id="no-delete-files">No</paper-button>
</div>
</div>
`,
15 * 1000 // 15 sec...
);
let yesBtn = document.querySelector("#yes-delete-files")
let noBtn = document.querySelector("#no-delete-files")
// On yes
yesBtn.onclick = () => {
toast.dismiss();
let success = () => {
ApplicationView.displayMessage(
`<iron-icon icon='delete' style='margin-right: 10px;'></iron-icon><div>
Files are now deleted!
</div>`,
3000
);
this.selected = {}
}
let index = 0;
let deleteFile_ = () => {
let f = files[index]
f.path = f.path.split("\\").join("/")
let path = f.path.substring(0, f.path.lastIndexOf("/"))
index++
let globule = this._file_explorer_.globule
if (f.isDir) {
generatePeerToken(globule, token => {
this._file_explorer_.globule.fileService.getPublicDirs(new GetPublicDirsRequest, { application: Application.application, domain: this._file_explorer_.globule.domain, token: token })
.then(rsp => {
// if the dir is public I will remove it entry from the list and keep the directory...
let dirs = rsp.getDirsList()
if (dirs.includes(f.path)) {
const rqst = new RemovePublicDirRequest
rqst.setPath(f.path)
generatePeerToken(globule, token => {
globule.fileService.removePublicDir(rqst, { application: Application.application, domain: globule.domain, token: token })
.then(rsp => {
delete dirs[getUuidByString(this._file_explorer_.globule.domain + "@/public")]
Model.publish("reload_dir_event", "/public", false);
})
.catch(err => { ApplicationView.displayMessage(err, 3000) })
})
} else {
generatePeerToken(globule, token => {
deleteDir(globule, f.path,
() => {
delete dirs[getUuidByString(this._file_explorer_.globule.domain + "@" + path)]
this._file_explorer_.globule.eventHub.publish("reload_dir_event", path, false);
if (index < Object.keys(this.selected).length) {
deleteFile_()
} else {
success()
}
},
err => { ApplicationView.displayMessage(err, 3000) }, token)
})
}
})
})
} else {
deleteFile(globule, f.path,
() => {
delete dirs[getUuidByString(this._file_explorer_.globule.domain + "@" + path)]
Model.publish("reload_dir_event", path, false);
if (index < Object.keys(this.selected).length) {
deleteFile_()
} else {
success()
}
},
err => { ApplicationView.displayMessage(err, 3000) })
}
}
// start file deletion...
deleteFile_()
}
noBtn.onclick = () => {
toast.dismiss();
}
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.renameMenuItem.action = () => {
// Display the rename input...
this.menu.rename()
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.fileInfosMenuItem.action = () => {
Model.eventHub.publish(`display_file_infos_${this._file_explorer_.id}_event`, this.menu.file, true)
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
this.titleInfosMenuItem.action = () => {
// So here I will create a new permission manager object and display it for the given file.
let file = this.menu.file
if (file.videos || file.titles || file.audios) {
Model.eventHub.publish(`display_media_infos_${this._file_explorer_.id}_event`, file, true)
} else {
if (file.mime.startsWith("video") || file.isDir) {
getVideoInfo(file, (videos) => {
if (videos.length > 0) {
Model.eventHub.publish(`display_media_infos_${this._file_explorer_.id}_event`, file, true)
// Remove it from it parent...
if (this.menu.parentNode) {
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
} else {
// get the title infos...
getTitleInfo(file, (titles) => {
if (titles.length > 0) {
Model.eventHub.publish(`display_media_infos_${this._file_explorer_.id}_event`, file, true)
if (this.menu.parentNode) {
// Remove it from it parent...
this.menu.close()
this.menu.parentNode.removeChild(this.menu)
}
} else {
// So here no video or title info exist for that file I will propose to the user
// to create a new video infos...
// Here I will ask the user for confirmation before actually delete the contact informations.
let toast = ApplicationView.displayMessage(
`
<style>
#yes-no-create-video-info-box{
display: flex;
flex-direction: column;
}
#yes-no-create-video-info-box globular-picture-card{
padding-bottom: 10px;
}
#yes-no-create-video-info-box div{
display: flex;
padding-bottom: 10px;
}
</style>
<div id="yes-no-create-video-info-box">
<div style="margin-bottom: 10px;">No informations was associated with that video file</div>
<img style="max-height: 100px; object-fit: contain; width: 100%;" src="${file.thumbnail}"></img>
<span style="font-size: .95rem; text-align: center;">${file.path.substring(file.path.lastIndexOf("/") + 1)}</span>
<div style="margin-top: 10px;">Do you want to create video/movie information? </div>
<div style="justify-content: flex-end;">
<paper-button raised id="yes-create-video-info">Yes</paper-button>
<paper-button raised id="no-create-video-info">No</paper-button>
</div>
</div>
`,
60 * 1000 // 60 sec...
);
let yesBtn = document.querySelector("#yes-create-video-info")
let noBtn = document.querySelector("#no-create-video-info")
// On yes
yesBtn.onclick = () => {
// So here I will ask witch type of information the user want's to generate, title, video or audio...
toast.dismiss();
let toast_ = ApplicationView.displayMessage(
`
<style>
</style>
<div style="display: flex; flex-direction: column;">
<div>
Please select the kind of information to create...
</div>
<img style="max-height: 100px; object-fit: contain; width: 100%; margin-top: 15px;" src="${file.thumbnail}"></img>
<paper-radio-group selected="video-option" style="margin-top: 15px;">
<paper-radio-button id="video-option" name="video-option"><span title="simple video ex. youtube">Video</span></paper-radio-button>
<paper-radio-button id="title-option" name="title-option"><span title="Movie">Movie or TV Episode/Serie</span></paper-radio-button>
</paper-radio-group>
<div st