def _clean_snapshot(request, device): """remove calibre book ids from snapshot uploads""" # the snapshot upload tells the upstream server all the books that are on the device # but it includes all books, not only the ones it thinks it got from the Amazon service # so we update the set of books that we know the device has # but don't update the list of books it should remove from the device if they are not found in the calibre library was_updated = False books_on_device = set() lines = [] for line in request.body_text().splitlines(True): if line.startswith(b'Type=EBOK,Key=') and len(line) == 50 + (line[-1] == ord('\n')): asin = str(line[14:50], 'ascii') # SHOULD be uuid if is_uuid(asin, 'EBOK'): books_on_device.add(asin) if features.scrub_uploads: was_updated = True continue elif line.startswith(b'Type=PDOC,Key=') and len(line) == 46 + (line[-1] == ord('\n')): asin = str(line[14:46], 'ascii') if is_uuid(asin, 'PDOC'): books_on_device.add(asin) if features.scrub_uploads: was_updated = True continue lines.append(line) if books_on_device: postprocess.enqueue(_process_books_on_device, device, books_on_device) if was_updated and not request.is_signed(): request.update_body(b''.join(lines)) return was_updated
def _process_xml(request, doc, device): books_on_device = set() book_nodes = [] was_modified = False x_annotations = qxml.get_child(doc, 'annotations') for x_book in qxml.list_children(x_annotations, 'book'): asin = x_book.getAttribute('key') if is_uuid(asin, x_book.getAttribute('type')): books_on_device.add(asin) x_annotations.removeChild(x_book) book_nodes.append(x_book) was_modified = True for x_collection in qxml.iter_children(x_annotations, 'collection'): for x_book in qxml.iter_children(x_collection, 'book'): asin = x_book.getAttribute('id') if is_uuid(asin, x_book.getAttribute('type')) and 'add' == x_book.getAttribute('action'): books_on_device.add(asin) if books_on_device or book_nodes: postprocess.enqueue(_process_sidecar_upload, device, books_on_device, book_nodes) if was_modified: qxml.remove_whitespace(x_annotations) if not len(x_annotations.childNodes): doc.removeChild(x_annotations) if not len(doc.childNodes): # there's no more content relevant to Amazon, just reply with an empty 200 raise ExceptionResponse() return was_modified
def _clean_snapshot(request, device): """remove calibre book ids from snapshot uploads""" # the snapshot upload tells the upstream server all the books that are on the device # but it includes all books, not only the ones it thinks it got from the Amazon service # so we update the set of books that we know the device has # but don't update the list of books it should remove from the device if they are not found in the calibre library was_updated = False books_on_device = set() lines = [] for line in request.body_text().splitlines(True): if line.startswith(b'Type=EBOK,Key='): asin = str(line[14:].strip(), 'ascii') if is_uuid(asin, 'EBOK'): books_on_device.add(asin) if features.scrub_uploads: was_updated = True continue elif line.startswith(b'Type=PDOC,Key='): asin = str(line[14:].strip(), 'ascii') if is_uuid(asin, 'PDOC'): books_on_device.add(asin) if features.scrub_uploads: was_updated = True continue elif line.startswith(b'ASIN='): # Android asin = str(line[5:].strip(), 'ascii') if is_uuid(asin): books_on_device.add(asin) if features.scrub_uploads: was_updated = True continue lines.append(line) if books_on_device: postprocess.enqueue(_process_books_on_device, device, books_on_device) if was_updated and not request.is_signed(): request.update_body(b''.join(lines)) return was_updated