Commit | Line | Data |
---|---|---|
41f446f4 | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
cf29e8a8 | 2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. |
41f446f4 CAW |
3 | # |
4 | # This program is free software: you can redistribute it and/or modify | |
5 | # it under the terms of the GNU Affero General Public License as published by | |
6 | # the Free Software Foundation, either version 3 of the License, or | |
7 | # (at your option) any later version. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU Affero General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
64da09e8 | 17 | import logging |
095fbdaf | 18 | import os |
64da09e8 | 19 | |
eace050a | 20 | from mediagoblin.db.util import atomic_update |
4a477e24 | 21 | from mediagoblin import mg_globals as mgg |
8e5f9746 | 22 | |
6506b1e2 | 23 | from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ |
8e5f9746 | 24 | |
64da09e8 | 25 | _log = logging.getLogger(__name__) |
41f446f4 | 26 | |
24eaf0fd | 27 | THUMB_SIZE = 180, 180 |
93214d8e | 28 | MEDIUM_SIZE = 640, 640 |
41f446f4 CAW |
29 | |
30 | ||
180bdbde | 31 | def create_pub_filepath(entry, filename): |
48a7ba1e | 32 | return mgg.public_store.get_unique_filepath( |
180bdbde | 33 | ['media_entries', |
eabe6b67 | 34 | unicode(entry._id), |
180bdbde E |
35 | filename]) |
36 | ||
28f364bd | 37 | class FilenameBuilder(object): |
4774cfa3 BS |
38 | """Easily slice and dice filenames. |
39 | ||
28f364bd | 40 | Initialize this class with an original file path, then use the fill() |
4774cfa3 BS |
41 | method to create new filenames based on the original. |
42 | ||
43 | """ | |
44 | MAX_FILENAME_LENGTH = 255 # VFAT's maximum filename length | |
095fbdaf BS |
45 | |
46 | def __init__(self, path): | |
28f364bd | 47 | """Initialize a builder from an original file path.""" |
095fbdaf BS |
48 | self.dirpath, self.basename = os.path.split(path) |
49 | self.basename, self.ext = os.path.splitext(self.basename) | |
50 | self.ext = self.ext.lower() | |
51 | ||
28f364bd BS |
52 | def fill(self, fmtstr): |
53 | """Build a new filename based on the original. | |
4774cfa3 | 54 | |
28f364bd BS |
55 | The fmtstr argument can include the following: |
56 | {basename} -- the original basename, with the extension removed | |
57 | {ext} -- the original extension, always lowercase | |
58 | ||
59 | If necessary, {basename} will be truncated so the filename does not | |
60 | exceed this class' MAX_FILENAME_LENGTH in length. | |
4774cfa3 BS |
61 | |
62 | """ | |
095fbdaf BS |
63 | basename_len = (self.MAX_FILENAME_LENGTH - |
64 | len(fmtstr.format(basename='', ext=self.ext))) | |
65 | return fmtstr.format(basename=self.basename[:basename_len], | |
66 | ext=self.ext) | |
67 | ||
68 | ||
6788b412 | 69 | def mark_entry_failed(entry_id, exc): |
2e5ea6b9 CAW |
70 | """ |
71 | Mark a media entry as having failed in its conversion. | |
72 | ||
243c3843 NY |
73 | Uses the exception that was raised to mark more information. If |
74 | the exception is a derivative of BaseProcessingFail then we can | |
75 | store extra information that can be useful for users telling them | |
76 | why their media failed to process. | |
2e5ea6b9 CAW |
77 | |
78 | Args: | |
79 | - entry_id: The id of the media entry | |
80 | ||
81 | """ | |
6788b412 CAW |
82 | # Was this a BaseProcessingFail? In other words, was this a |
83 | # type of error that we know how to handle? | |
84 | if isinstance(exc, BaseProcessingFail): | |
85 | # Looks like yes, so record information about that failure and any | |
86 | # metadata the user might have supplied. | |
82cd9683 | 87 | atomic_update(mgg.database.MediaEntry, |
6788b412 | 88 | {'_id': entry_id}, |
82cd9683 E |
89 | {u'state': u'failed', |
90 | u'fail_error': exc.exception_path, | |
91 | u'fail_metadata': exc.metadata}) | |
6788b412 | 92 | else: |
baae1578 | 93 | _log.warn("No idea what happened here, but it failed: %r", exc) |
6788b412 CAW |
94 | # Looks like no, so just mark it as failed and don't record a |
95 | # failure_error (we'll assume it wasn't handled) and don't record | |
96 | # metadata (in fact overwrite it if somehow it had previous info | |
97 | # here) | |
82cd9683 | 98 | atomic_update(mgg.database.MediaEntry, |
6788b412 | 99 | {'_id': entry_id}, |
82cd9683 E |
100 | {u'state': u'failed', |
101 | u'fail_error': None, | |
102 | u'fail_metadata': {}}) | |
4a477e24 CAW |
103 | |
104 | ||
8e5f9746 JW |
105 | class BaseProcessingFail(Exception): |
106 | """ | |
107 | Base exception that all other processing failure messages should | |
108 | subclass from. | |
109 | ||
110 | You shouldn't call this itself; instead you should subclass it | |
111 | and provid the exception_path and general_message applicable to | |
112 | this error. | |
113 | """ | |
114 | general_message = u'' | |
115 | ||
116 | @property | |
117 | def exception_path(self): | |
118 | return u"%s:%s" % ( | |
119 | self.__class__.__module__, self.__class__.__name__) | |
120 | ||
121 | def __init__(self, **metadata): | |
122 | self.metadata = metadata or {} | |
123 | ||
124 | ||
125 | class BadMediaFail(BaseProcessingFail): | |
4a477e24 | 126 | """ |
8e5f9746 JW |
127 | Error that should be raised when an inappropriate file was given |
128 | for the media type specified. | |
4a477e24 | 129 | """ |
8e5f9746 | 130 | general_message = _(u'Invalid file given for media type.') |