Exemplo n.º 1
0
 def authorise(self, level):
     with Busy():
         if self.session.permitted(level):
             return True
         # do full authentication procedure
         auth_url = self.session.get_auth_url(level)
     auth_code = self.auth_dialog(auth_url)
     if not auth_code:
         return False
     with Busy():
         return self.session.get_access_token(auth_code, level)
Exemplo n.º 2
0
 def search(self, search_string=None):
     if not search_string:
         search_string = self.edit_box.lineEdit().text()
         self.edit_box.clearEditText()
     if not search_string:
         return
     self.search_string = search_string
     self.clear_search()
     params = {
         'q': search_string,
         'format': 'json',
         'polygon': '0',
         'addressdetails': '0',
     }
     if 'bounds' in self.map_status:
         bounds = self.map_status['bounds']
         params['viewbox'] = '{:.8f},{:.8f},{:.8f},{:.8f}'.format(
             bounds[3], bounds[0], bounds[1], bounds[2])
     headers = {'user-agent': 'Photini/' + __version__}
     with Busy():
         try:
             rsp = requests.get('http://nominatim.openstreetmap.org/search',
                                params=params,
                                headers=headers)
         except Exception as ex:
             self.logger.error(str(ex))
             return
     if rsp.status_code >= 400:
         return
     for result in rsp.json():
         self.search_result(result['boundingbox'][0],
                            result['boundingbox'][3],
                            result['boundingbox'][1],
                            result['boundingbox'][2],
                            result['display_name'])
Exemplo n.º 3
0
 def query(self, params):
     params['key'] = self.api_key
     params['abbrv'] = '1'
     params['no_annotations'] = '1'
     lang, encoding = locale.getdefaultlocale()
     if lang:
         params['language'] = lang
     with Busy():
         self.rate_limit()
         try:
             rsp = requests.get(
                 'https://api.opencagedata.com/geocode/v1/json',
                 params=params,
                 timeout=5)
         except Exception as ex:
             logger.error(str(ex))
             return []
     if rsp.status_code >= 400:
         logger.error('Search error %d', rsp.status_code)
         return []
     rsp = rsp.json()
     status = rsp['status']
     if status['code'] != 200:
         logger.error('Search error %d: %s', status['code'],
                      status['message'])
         return []
     if rsp['total_results'] < 1:
         logger.error('No results found')
         return []
     rate = rsp['rate']
     self.block_timer.setInterval(5000 * rate['limit'] //
                                  max(rate['remaining'], 1))
     return rsp['results']
Exemplo n.º 4
0
 def copy_selected(self):
     if self.import_in_progress:
         # user has clicked while import is still cancelling
         self.copy_button.setChecked(False)
         return
     self.import_in_progress = True
     copy_list = []
     for item in self.file_list_widget.selectedItems():
         name = item.data(Qt.UserRole)
         copy_list.append(self.file_data[name])
     last_item = None, datetime.min
     with Busy():
         for item in self.source.copy_files(copy_list):
             if not item:
                 self._fail()
                 break
             if self.abort_copy():
                 break
             self.image_list.open_file(item['dest_path'])
             if self.abort_copy():
                 break
             if last_item[1] < item['timestamp']:
                 last_item = item['dest_path'], item['timestamp']
             QtCore.QCoreApplication.flush()
     if last_item[0]:
         self.config_store.set(self.config_section, 'last_transfer',
                               last_item[1].isoformat(' '))
         self.image_list.done_opening(last_item[0])
     self.show_file_list()
     self.copy_button.setChecked(False)
     self.import_in_progress = False
Exemplo n.º 5
0
 def do_search(self, query, params={}):
     self.disable_search()
     params['key'] = self.api_key
     params['q'] = query
     params['abbrv'] = '1'
     params['no_annotations'] = '1'
     lang, encoding = locale.getdefaultlocale()
     if lang:
         params['language'] = lang
     with Busy():
         try:
             rsp = requests.get(
                 'https://api.opencagedata.com/geocode/v1/json',
                 params=params)
         except Exception as ex:
             self.logger.error(str(ex))
             return None
     if rsp.status_code >= 400:
         self.logger.error('Search error %d', rsp.status_code)
         return None
     rsp = rsp.json()
     status = rsp['status']
     if status['code'] != 200:
         self.logger.error(
             'Search error %d: %s', status['code'], status['message'])
         return None
     rate = rsp['rate']
     self.block_timer.setInterval(
         10000 * rate['limit'] // max(rate['remaining'], 1))
     return rsp
Exemplo n.º 6
0
    def delete_album(self):
        album = self.current_album
        if int(album.numphotos.text) > 0:
            if QtWidgets.QMessageBox.question(
                    self, self.tr('Delete album'),
                    self.tr("""Are you sure you want to delete the album "{0}"?
Doing so will remove the album and its photos from all Google products."""
                            ).format(album.title.text),
                    QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
                    QtWidgets.QMessageBox.Cancel
            ) == QtWidgets.QMessageBox.Cancel:
                return
        with Busy():
            self.timer.stop()
            self.album_changed = False
            if not self.session.permitted('write'):
                self.refresh()
                return
            self.current_album = None
            self.upload_config.show_album(None)
            QtWidgets.QApplication.processEvents()
            self.session.delete_album(album)
            self.upload_config.albums.removeItem(
                self.upload_config.albums.findData(album.id.text))
            self.set_current_album()
Exemplo n.º 7
0
 def refresh(self, force=False):
     with Busy():
         self.connected = (self.user_connect.isChecked()
                           and self.session.permitted('read'))
         if self.connected:
             self.user_connect.setText(
                 translate('PhotiniUploader', 'Log out'))
             if force:
                 # load_user_data can be slow, so only do it when forced
                 try:
                     self.load_user_data()
                 except Exception as ex:
                     logger.error(ex)
                     self.connected = False
         if not self.connected:
             self.user_connect.setText(
                 translate('PhotiniUploader', 'Log in'))
             # clearing user data is quick so do it anyway
             self.load_user_data()
         self.user_connect.setChecked(self.connected)
         self.upload_config.setEnabled(self.connected
                                       and not self.upload_worker)
         self.user_connect.setEnabled(not self.upload_worker)
         # enable or disable upload button
         self.new_selection(self.image_list.get_selected_images())
Exemplo n.º 8
0
 def do_bing_geocode(self, query='', params={}):
     self.disable_search()
     params['key'] = self.map_status['session_id']
     url = 'http://dev.virtualearth.net/REST/v1/Locations'
     if query:
         url += '/' + query
     with Busy():
         try:
             rsp = requests.get(url, params=params, timeout=5)
         except Exception as ex:
             logger.error(str(ex))
             return []
     if rsp.status_code >= 400:
         logger.error('Search error %d', rsp.status_code)
         return []
     if rsp.headers['X-MS-BM-WS-INFO'] == '1':
         logger.error('Server overload')
     else:
         # re-enable search immediately rather than after timeout
         self.enable_search()
     rsp = rsp.json()
     if rsp['statusCode'] != 200:
         logger.error('Search error %d: %s', rsp['statusCode'],
                      rsp['statusDescription'])
         return []
     resource_sets = rsp['resourceSets']
     if not resource_sets:
         logger.error('No results found')
         return []
     return resource_sets
Exemplo n.º 9
0
 def sync_metadata(self):
     # make list of known photo ids
     photo_ids = {}
     unknowns = []
     for image in self.image_list.get_selected_images():
         for keyword in image.metadata.keywords or []:
             name_pred, sep, value = keyword.partition('=')
             if name_pred == ID_TAG:
                 photo_ids[value] = image
                 break
         else:
             unknowns.append(image)
     # try to find unknowns on Flickr
     for image in unknowns:
         for photo in self._find_on_flickr(image):
             if photo['id'] in photo_ids:
                 continue
             match = self._find_local(photo, unknowns)
             if match:
                 match.metadata.keywords = list(
                     match.metadata.keywords or []) + [
                         '{}={}'.format(ID_TAG, photo['id'])]
                 photo_ids[photo['id']] = match
                 unknowns.remove(match)
     # merge Flickr metadata into file
     with Busy():
         for photo_id, image in photo_ids.items():
             self._merge_metadata(photo_id, image)
Exemplo n.º 10
0
 def _save_files(self, images=[]):
     self._flush_editing()
     if_mode = self.app.config_store.get('files', 'image', True)
     sc_mode = self.app.config_store.get('files', 'sidecar', 'auto')
     force_iptc = self.app.config_store.get('files', 'force_iptc', False)
     keep_time = self.app.config_store.get('files', 'preserve_timestamps',
                                           'now')
     if isinstance(keep_time, bool):
         # old config format
         keep_time = ('now', 'keep')[keep_time]
     if not images:
         images = self.images
     with Busy():
         for image in images:
             if keep_time == 'taken' and image.metadata.date_taken:
                 file_times = (
                     image.file_times[0],
                     image.metadata.date_taken['datetime'].timestamp())
             elif keep_time == 'keep':
                 file_times = image.file_times
             else:
                 file_times = None
             image.metadata.save(if_mode=if_mode,
                                 sc_mode=sc_mode,
                                 force_iptc=force_iptc,
                                 file_times=file_times)
     unsaved = any([image.metadata.changed() for image in self.images])
     self.new_metadata.emit(unsaved)
Exemplo n.º 11
0
 def show_album(self, album):
     if album:
         self.albums.setCurrentIndex(self.albums.findData(album.id.text))
         self.widgets['description'].set_value(album.summary.text)
         self.widgets['location'].setText(album.location.text)
         self.widgets['access'].setCurrentIndex(
             self.widgets['access'].findData(album.access.text))
         self.widgets['timestamp'].setDateTime(
             QtCore.QDateTime.fromTime_t(int(album.timestamp.text) // 1000))
         if album.group.thumbnail is not None:
             QtWidgets.QApplication.processEvents()
             with Busy():
                 url = album.group.thumbnail[0].get('url')
                 image = QtGui.QPixmap(160, 160)
                 try:
                     image.loadFromData(urlopen(url).read())
                 except HTTPError as ex:
                     paint = QtGui.QPainter(image)
                     paint.fillRect(image.rect(), Qt.black)
                     paint.setPen(Qt.white)
                     paint.drawText(image.rect(),
                                    Qt.AlignLeft | Qt.TextWordWrap, str(ex))
                     paint.end()
                 self.album_thumb.setPixmap(image)
     else:
         self.widgets['description'].set_value(None)
         self.widgets['location'].clear()
         self.widgets['timestamp'].clear()
         self.album_thumb.clear()
Exemplo n.º 12
0
 def do_google_geocode(self, params):
     self.disable_search()
     params['key'] = self.api_key
     lang, encoding = locale.getdefaultlocale()
     if lang:
         params['language'] = lang
     url = 'https://maps.googleapis.com/maps/api/geocode/json'
     with Busy():
         try:
             rsp = requests.get(url, params=params, timeout=5)
         except Exception as ex:
             logger.error(str(ex))
             return []
     if rsp.status_code >= 400:
         logger.error('Search error %d', rsp.status_code)
         return []
     self.enable_search()
     rsp = rsp.json()
     if rsp['status'] != 'OK':
         if 'error_message' in rsp:
             logger.error('Search error: %s: %s', rsp['status'],
                          rsp['error_message'])
         else:
             logger.error('Search error: %s', rsp['status'])
         return []
     results = rsp['results']
     if not results:
         logger.error('No results found')
         return []
     return results
Exemplo n.º 13
0
 def _save_files(self, images=[]):
     if_mode = eval(self.app.config_store.get('files', 'image', 'True'))
     sc_mode = self.app.config_store.get('files', 'sidecar', 'auto')
     force_iptc = eval(
         self.app.config_store.get('files', 'force_iptc', 'False'))
     keep_time = eval(
         self.app.config_store.get('files', 'preserve_timestamps', 'False'))
     if not images:
         images = self.images
     with Busy():
         for image in images:
             if keep_time:
                 file_times = image.file_times
             else:
                 file_times = None
             image.metadata.save(if_mode=if_mode,
                                 sc_mode=sc_mode,
                                 force_iptc=force_iptc,
                                 file_times=file_times)
     unsaved = False
     for image in self.images:
         if image.metadata.changed():
             unsaved = True
             break
     self.new_metadata.emit(unsaved)
Exemplo n.º 14
0
 def query(self, params, url):
     params['key'] = self.api_key
     with Busy():
         self.rate_limit()
         try:
             rsp = requests.get(url, params=params, timeout=5)
         except Exception as ex:
             logger.error(str(ex))
             return []
     if rsp.status_code >= 400:
         logger.error('Search error %d', rsp.status_code)
         return []
     if rsp.headers['X-MS-BM-WS-INFO'] == '1':
         logger.error(
             translate('MapTabBing', 'Server overload, please try again'))
         self.block_timer.start(5000)
     rsp = rsp.json()
     if rsp['statusCode'] != 200:
         logger.error('Search error %d: %s', rsp['statusCode'],
                      rsp['statusDescription'])
         return []
     resource_sets = rsp['resourceSets']
     if not resource_sets:
         logger.error('No results found')
         return []
     return resource_sets
Exemplo n.º 15
0
 def save_changes(self):
     self.timer.stop()
     if not self.album_changed:
         return
     self.album_changed = False
     with Busy():
         self.session.edit_node(self.current_album)
         self.set_current_album(self.current_album.id.text)
Exemplo n.º 16
0
 def fix_missing_thumbs(self):
     with Busy():
         for image in self.get_images():
             thumb = image.metadata.thumbnail
             if not thumb or not thumb['image']:
                 if image.regenerate_thumbnail():
                     image.load_thumbnail()
     self.image_list_changed.emit()
Exemplo n.º 17
0
 def list_files(self):
     file_data = {}
     if self.source:
         with Busy():
             file_data = self.source.get_file_data()
             if file_data is None:
                 self._fail()
                 return
     self._new_file_list(file_data)
Exemplo n.º 18
0
 def log_in(self, do_auth=True):
     with DisableWidget(self.user_connect):
         with Busy():
             connect = self.session.connect()
         if connect is None:
             # can't reach server
             return
         if do_auth and not connect:
             self.authorise()
Exemplo n.º 19
0
 def select_album(self, album_id):
     with Busy():
         self.save_changes()
         if not self.session.permitted('read'):
             self.refresh()
             return
         self.current_album = None
         self.upload_config.show_album(None)
         QtWidgets.QApplication.processEvents()
         self.set_current_album(album_id)
Exemplo n.º 20
0
 def get_address(self):
     lat, lon = self.coords.get_value().split(',')
     params = {
         'lat': lat.strip(),
         'lon': lon.strip(),
         'zoom': '18',
         'format': 'json',
         'addressdetails': '1',
     }
     headers = {'user-agent': 'Photini/' + __version__}
     with Busy():
         try:
             rsp = requests.get(
                 'http://nominatim.openstreetmap.org/reverse',
                 params=params,
                 headers=headers)
         except Exception as ex:
             self.logger.error(str(ex))
             return
     if rsp.status_code >= 400:
         return
     rsp = rsp.json()
     if 'error' in rsp:
         self.logger.error(rsp['error'])
         return
     address = rsp['address']
     location = []
     for iptc_key, osm_keys in (('world_region', ()), ('country_code',
                                                       ('country_code', )),
                                ('country_name', ('country', )),
                                ('province_state',
                                 ('region', 'county', 'state_district',
                                  'state')), ('city',
                                              ('hamlet', 'locality',
                                               'neighbourhood', 'village',
                                               'suburb', 'town',
                                               'city_district', 'city')),
                                ('sublocation',
                                 ('building', 'house_number', 'footway',
                                  'pedestrian', 'road'))):
         element = []
         for key in osm_keys:
             if key not in address:
                 continue
             if address[key] not in element:
                 element.append(address[key])
             del (address[key])
         location.append(', '.join(element))
     # put remaining keys in sublocation
     for key in address:
         if key in ('postcode', ):
             continue
         location[-1] = '{}: {}, {}'.format(key, address[key], location[-1])
     self.set_location_taken(*location)
Exemplo n.º 21
0
 def save_files(self):
     if_mode = eval(self.app.config_store.get('files', 'image', 'True'))
     sc_mode = self.app.config_store.get('files', 'sidecar', 'auto')
     force_iptc = eval(
         self.app.config_store.get('files', 'force_iptc', 'False'))
     unsaved = False
     with Busy():
         for image in self.images:
             image.metadata.save(if_mode, sc_mode, force_iptc)
             unsaved = unsaved or image.metadata.changed()
     self.new_metadata.emit(unsaved)
Exemplo n.º 22
0
 def connection_changed(self, connected):
     if connected:
         with Busy():
             self.show_user(*self.session.get_user())
             self.show_album_list(self.session.get_albums())
     else:
         self.show_user(None, None)
         self.show_album_list([])
     self.user_connect.set_checked(connected)
     self.upload_config.setEnabled(connected and not self.upload_worker)
     self.user_connect.setEnabled(not self.upload_worker)
     self.enable_upload_button()
Exemplo n.º 23
0
 def select_album(self, index):
     if not self.authorise('read'):
         self.refresh(force=True)
         return
     album_id = self.upload_config.widgets['album_choose'].itemData(index)
     if album_id == 'me':
         self.upload_config.show_album({}, None)
         return
     with Busy():
         album, picture = self.session.get_album(
             album_id, 'cover_photo,description,location,name')
         self.upload_config.show_album(album, picture)
Exemplo n.º 24
0
 def _sort_thumbnails(self):
     sort_date = self.sort_date.isChecked()
     self.app.config_store.set('controls', 'sort_date', str(sort_date))
     with Busy():
         if sort_date:
             self.images.sort(key=self._date_key)
         else:
             self.images.sort(key=lambda x: x.path)
         for image in self.images:
             self.show_thumbnail(image, False)
     if self.last_selected:
         self.app.processEvents()
         self.scroll_area.ensureWidgetVisible(self.last_selected)
     self.image_list_changed.emit()
Exemplo n.º 25
0
 def find_photos(self, min_taken_date, max_taken_date):
     # search Flickr
     page = 1
     while True:
         with Busy():
             rsp = self.api_call(
                 'flickr.people.getPhotos',
                 user_id='me', page=page, extras='date_taken,url_t',
                 min_taken_date=min_taken_date.strftime('%Y-%m-%d %H:%M:%S'),
                 max_taken_date=max_taken_date.strftime('%Y-%m-%d %H:%M:%S'))
             if not ('photos' in rsp and rsp['photos']['photo']):
                 return
         for photo in rsp['photos']['photo']:
             yield photo
         page += 1
Exemplo n.º 26
0
 def new_album(self):
     with Busy():
         self.save_changes()
         if not self.session.permitted('write'):
             self.refresh()
             return
         self.current_album = None
         self.upload_config.show_album(None)
         QtWidgets.QApplication.processEvents()
         album = PicasaNode()
         album.title.text = self.tr('New album')
         album.category.set('scheme', nsmap['gd'] + '#kind')
         album.category.set('term', nsmap['gphoto'] + '#album')
         album = self.session.new_album(album)
         self.upload_config.albums.addItem(album.title.text, album.id.text)
         self.set_current_album(album.id.text)
Exemplo n.º 27
0
 def copy_selected(self):
     if self.import_in_progress:
         # user has clicked while import is still cancelling
         self.copy_button.setChecked(False)
         return
     self.import_in_progress = True
     copy_list = []
     for item in self.file_list_widget.selectedItems():
         name = item.text().split()[0]
         copy_list.append(self.file_data[name])
     last_item = None, datetime.min
     with self.session() as session:
         with Busy():
             for item in copy_list:
                 dest_path = item['dest_path']
                 dest_dir = os.path.dirname(dest_path)
                 if self.abort_copy():
                     break
                 if not os.path.isdir(dest_dir):
                     os.makedirs(dest_dir)
                 try:
                     camera_file = session.copy_file(item, dest_path)
                     if self.abort_copy():
                         break
                     if camera_file:
                         camera_file.save(dest_path)
                 except gp.GPhoto2Error as ex:
                     self.logger.error(str(ex))
                     self._fail()
                     break
                 timestamp = item['timestamp']
                 if last_item[1] < timestamp:
                     last_item = dest_path, timestamp
                 if self.abort_copy():
                     break
                 self.image_list.open_file(dest_path)
                 if self.abort_copy():
                     break
                 QtCore.QCoreApplication.flush()
     if last_item[0]:
         self.config_store.set(self.config_section, 'last_transfer',
                               last_item[1].isoformat(' '))
         self.image_list.done_opening(last_item[0])
     self.show_file_list()
     self.copy_button.setChecked(False)
     self.import_in_progress = False
Exemplo n.º 28
0
 def find_photos(self, min_taken_date, max_taken_date):
     # search Flickr
     page = 1
     while True:
         with Busy():
             try:
                 rsp = self.api.people.getPhotos(
                     user_id='me', page=page, extras='date_taken,url_t',
                     min_taken_date=min_taken_date.strftime('%Y-%m-%d %H:%M:%S'),
                     max_taken_date=max_taken_date.strftime('%Y-%m-%d %H:%M:%S'))
                 if rsp['stat'] != 'ok' or not rsp['photos']['photo']:
                     return
             except Exception as ex:
                 logger.error(str(ex))
                 self.disconnect()
                 return
         for photo in rsp['photos']['photo']:
             yield photo
         page += 1
Exemplo n.º 29
0
 def regenerate_thumbnail(self):
     # DCF spec says thumbnail must be 160 x 120, so other aspect
     # ratios are padded with black
     with Busy():
         # first try using FFmpeg to make thumbnail
         data, fmt, w, h = self.make_thumb_ffmpeg()
         if not data:
             # use PIL or Qt
             qt_im = self.get_qt_image()
             if not qt_im:
                 return
             if PIL:
                 data, fmt, w, h = self.make_thumb_PIL(qt_im)
             else:
                 data, fmt, w, h = self.make_thumb_Qt(qt_im)
         # set thumbnail
         self.metadata.thumbnail = data, fmt, w, h
         # reload thumbnail
         self.load_thumbnail()
Exemplo n.º 30
0
 def list_files(self):
     file_data = {}
     if self.session_factory:
         with self.session() as session:
             with Busy():
                 try:
                     file_list = session.list_files()
                 except gp.GPhoto2Error:
                     # camera is no longer visible
                     self._fail()
                     return
                 for path in file_list:
                     try:
                         info = session.get_file_info(path)
                     except gp.GPhoto2Error:
                         self._fail()
                         return
                     file_data[info['name']] = info
     self._new_file_list(file_data)