Passed
Branch master (929f74)
by Cyb3r
01:56
created

MetaStalk.main.MetaStalk.parse_files()   A

Complexity

Conditions 5

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 9
nop 2
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 5
rs 9.3333
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2 1
"""Main function of MetaStalk.
3
Run get any metadata from photos
4
and creates graphs from the metadata using MetaStalk.Modules"""
5 1
import argparse
6 1
from collections import OrderedDict
7 1
import os
8 1
import logging
9 1
import timeit
10 1
import exifread
11 1
import MetaStalk.utils as utils
12 1
import MetaStalk.modules as modules
13
14
15 1
class MetaStalk():
16
    """MetaStalk.
17
    ---
18
19
    Main Class for all MetaStalk work
20
    """
21 1
    def __init__(self):
22 1
        self.log = logging.getLogger("MetaStalk")
23 1
        self.t_start = timeit.default_timer()
24 1
        self.valid, self.invalid = [], []
25 1
        self.plots = {}
26 1
        self.heic = utils.check_heic()
27
28 1
    def run(self, args):
29
        """Run
30
31
        Process files and generates graphs
32
33
        Arguments:
34
            args {argparse.Namespace} -- The arguments from start()
35
            log {logging.Logger} -- Logger
36
        """
37 1
        self.parse_files(args.files)
38
39 1
        self.plots = {
40
            "Stats": modules.stats(self.valid, self.invalid),
41
            "GPS": modules.gps_check(self.valid),
42
            "Timestamp": modules.date_time(self.valid),
43
            "Model": modules.pie_chart(self.valid, "Image Model"),
44
            "Manufacturer": modules.pie_chart(self.valid, "Image Make"),
45
            "Focal": modules.pie_chart(self.valid, "EXIF FocalLength"),
46
            "Producer": modules.pie_chart(self.valid, "Image Software")
47
        }
48 1
        if args.alphabetic:
49 1
            self.plots = OrderedDict(sorted(self.plots.items()))
50 1
        if args.export:
51 1
            utils.export(args.export, args.output, self.plots)
52
53 1
        utils.graph(self.plots, self.t_start, args.test, args.no_open)
54
55 1
    def parse_files(self, path_list: list):
56
        """parse_files
57
        ---
58
59
        Use to complete the direcotry parsing and file adding.
60
61
        Arguments:
62
            files {list} -- The list of paths to search for files
63
        """
64 1
        for path in path_list:
65 1
            if os.path.isdir(path):
66 1
                self.log.debug("Detected path as a directory")
67 1
                for root, _, files in os.walk(path):
68 1
                    for item in files:
69 1
                        item_path = os.path.join(root, item)
70 1
                        self.file_search(item_path)
71
            else:
72 1
                self.file_search(path)
73
74 1
    def file_search(self, parse_file: str):
75
        """file_search
76
77
        Used to append files if the path is not a directory.
78
79
        Arguments
80
            parse_files {str} -- Name of the file to parse.
81
        """
82 1
        if parse_file.lower().endswith(("heic", "heif")) and self.heic:
83
            tags = utils.parse_heic(parse_file)
84
        else:
85 1
            with open(parse_file, "rb") as f:
86 1
                tags = exifread.process_file(f)
87 1
                f.close()
88 1
        if tags:
89 1
            tags["item"] = parse_file
90 1
            self.valid.append(tags)
91 1
            self.log.debug("%s has metadata", parse_file)
92
        else:
93 1
            self.invalid.append(parse_file)
94 1
            self.log.debug("%s has no metadata data", parse_file)
95
96
97 1
def start():
98
    """ start
99
    ---
100
101
    Function needed to start MetaStalk. Does all the argument parsing.
102
    """
103 1
    parser = argparse.ArgumentParser(prog="MetaStalk",
104
                                     description="Tool to graph "
105
                                                 "image metadata.")
106 1
    parser.add_argument('files', nargs='*', default=None,
107
                        help='Path of photos to check.')
108 1
    parser.add_argument("-a", "--alphabetic", help="Sorts charts in alphabetical order rather than"
109
                        " the default order", default=False, action="store_true")
110 1
    parser.add_argument('-d', '--debug', help="Sets logging level to DEBUG.",
111
                        action="store_const", dest="loglevel",
112
                        const=logging.DEBUG, default=logging.WARNING)
113 1
    parser.add_argument("-e", "--export", choices=["pdf", "svg", "webp", "jpeg", "png",
114
                                                   "html", "html_offline"],
115
                        help="Exports the graphs rather than all on one webpage")
116 1
    parser.add_argument("--no-open", help="Will only start the server and not open the browser"
117
                        " to view it", default=False, action="store_true")
118 1
    parser.add_argument("-o", "--output", default="metastalk_exports",
119
                        help="The name of the directory to output exports to. "
120
                             "Will be created if it does not exist. "
121
                             "Defaults to metastalk_exports.")
122 1
    parser.add_argument('-t', '--test', default=False, action="store_true",
123
                        help='Does not show the graphs at the end.')
124 1
    parser.add_argument("-v", "--verbose", help="Sets logging level to INFO",
125
                        action="store_const", dest="loglevel",
126
                        const=logging.INFO)
127 1
    args = parser.parse_args()
128 1
    log = utils.make_logger("MetaStalk", args.loglevel)
129 1
    log.info("MetaStalk starting")
130 1
    if not args.files:
131 1
        log.error("ERROR: No path was inputted.")
132 1
        raise FileNotFoundError("No path was inputted.")
133
    metastalk = MetaStalk()  # pragma: no cover
134
    metastalk.run(args)  # pragma: no cover
135