zhongrj
2025-11-24 276323dce9613867abb3f58a4cc2abbfb2fd0dea
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
97
98
99
100
101
102
103
104
105
from abc import ABC, abstractmethod
import requests
from os import path
from app.plugins import logger
 
VALID_IMAGE_EXTENSIONS = ['.tiff', '.tif', '.png', '.jpeg', '.jpg']
 
class CloudPlatform(ABC):
    """A Cloud Platform is an online platform that can store files. For example Piwigo, Dropbox, Google Drive.
       Platforms have the concept of a folder or album, where files are stored. We will use the platform's API to 
       retrieve all the images in those folders, and import them into WebODM"""
 
    def __init__(self, name, folder_url_example):
        self.name = name
        self.folder_url_example = folder_url_example
  
    def verify_folder_url(self, folder_url):
        try:
            # Parse the url and get all necessary information
            information = self.parse_url(folder_url)
            # Define the API url we will call to assert that the folder exists and is valid
            folder_api_url = self.build_folder_api_url(information)
            # Call the API
            payload = self.call_api(folder_api_url)
            # Parse payload into a Folder instance
            return self.parse_payload_into_folder(folder_url, payload)
        except Exception as e:
            logger.error(str(e))
            return None
        
  
    def import_from_folder(self, folder_url):
        # Verify the url
        if self.verify_folder_url(folder_url) == None:
            raise Exception('Invalid URL')
 
        # Parse the url and get all necessary information
        information = self.parse_url(folder_url)
        # Define the API url we will call to get all the files in the folder
        folder_api_url = self.build_list_files_in_folder_api_url(information)
        # Call the API
        payload = self.call_api(folder_api_url)
        # Parse the payload into File instances
        files = self.parse_payload_into_files(payload)
        # Let the specific platform do some processing with the files (if necessary)
        files = self.platform_file_processing(files)
        # Return all the valid files
        return [file for file in files if file.is_valid()]
  
    def call_api(self, api_url):
        response = requests.get(api_url, timeout=10)
        response.raise_for_status()
        return response.json()
 
    def platform_file_processing(self, files):
        """This method does nothing, but each platform might want to do some processing of the files and they can, by overriding this method"""
        return files
  
    def serialize(self, **kwargs):
        return {'name': self.name, 'folder_url_example': self.folder_url_example, 'type': 'platform'} 
  
    @abstractmethod
    def parse_url(self, url):
        """Parse the given url and return necessary information to prepare the next requests"""
 
    @abstractmethod
    def build_list_files_in_folder_api_url(self, information):
        """Build the api url from the parsed information. This API should list all the files in the folder"""
 
    @abstractmethod
    def build_folder_api_url(self, information):
        """Build the api url from the parsed information. This API should return the name (and maybe amount of files) for the folder"""
 
    @abstractmethod
    def parse_payload_into_folder(self, original_url, payload):
        """Parse the api payload and return a Folder instance"""
  
    @abstractmethod
    def parse_payload_into_files(self, payload):
        """Parse the api payload and return File instances"""
 
class Folder:
    def __init__(self, name, url, images_count = -1, **kwargs):
        self.name = name
        self.url = url
        self.images_count = images_count
        self.other = kwargs
    
    def serialize(self):
        return {'name': self.name, 'url': self.url, 'images_count': self.images_count}
 
class File:
    def __init__(self, name, url, **kwargs):
        self.name = name
        self.url = url
        self.other = kwargs
    
    def is_valid(self):
        """Only keep files that are images, or that are named 'gcp_list.txt'"""
        _, file_extension = path.splitext(self.name)
        return file_extension.lower() in VALID_IMAGE_EXTENSIONS or self.name == 'gcp_list.txt'
    
    def serialize(self):
        return {'name': self.name, 'url': self.url}