def restore_necessary_files(): # Restore the appropriate media files and thumbnail files # for any media currently in the database. # Use the python models to do this. if not deleted_dir: return filename_pairs = [] for media in DBSession.query(Media).all(): for thumb in thumb_paths(media).values(): filename_pairs.append(( thumb.replace(m_img_dir, m_deleted_dir), thumb )) for file in media.files: if file.file_path: filename_pairs.append(( file.file_path.replace(media_dir, m_deleted_dir), file.file_path )) for podcast in DBSession.query(Podcast).all(): for thumb in thumb_paths(podcast).values(): filename_pairs.append(( thumb.replace(p_img_dir, p_deleted_dir), thumb )) for src, dest in filename_pairs: if os.path.exists(src): if DEBUG: print "Moving %s to %s" % (src, dest) shutil.move(src, dest)
def backup_files(dump_dir): # Backup all files (media files, thumbs) referenced by an object in the DB # to the provided dump_dir. # TODO: display errors when file operations fail if dump_dir == "/": return 1, "Dump Files directory should never be the root directory, '/'" # normalize dirname dump_dir = dump_dir.rstrip(os.sep) + os.sep # These are the directories we will write to. media_thumb_dir = dump_dir + Media._thumb_dir podcast_thumb_dir = dump_dir + Podcast._thumb_dir media_files_dir = dump_dir + "media_files" # Initialize our default paths to backup default_images = ["news.jpg", "newm.jpg", "newl.jpg"] media_thumbs = [m_img_dir + os.sep + img for img in default_images] podcast_thumbs = [p_img_dir + os.sep + img for img in default_images] media_files = [] # Add the media thumbs and media files for media in DBSession.query(Media).all(): file_paths = [file_path(f) for f in media.files] media_files += [fp for fp in file_paths if fp] media_thumbs += thumb_paths(media).values() # Add the podcast thumbs for podcast in DBSession.query(Podcast).all(): podcast_thumbs += thumb_paths(podcast).values() # Ensure the necessary directories exist. assert os.path.isdir(dump_dir) for subdir in (media_thumb_dir, media_files_dir, podcast_thumb_dir): if not os.path.exists(subdir): os.mkdir(subdir) assert os.path.isdir(subdir) empty_dir(subdir) # Copy over all of the files: sources_dests = ( (media_thumbs, media_thumb_dir), (media_files, media_files_dir), (podcast_thumbs, podcast_thumb_dir), ) for sources, dest_dir in sources_dests: for src in sources: if DEBUG: print "Copying %s to %s%s" % (src, dest_dir, os.sep) shutil.copy2(src, dest_dir) return ( 0, "%d thumbnails and %d media files successfully backed up" % (len(media_thumbs) + len(podcast_thumbs), len(media_files)), )
def backup_files(dump_dir): # Backup all files (media files, thumbs) referenced by an object in the DB # to the provided dump_dir. # TODO: display errors when file operations fail if dump_dir == '/': return 1, "Dump Files directory should never be the root directory, '/'" # normalize dirname dump_dir = dump_dir.rstrip(os.sep) + os.sep # These are the directories we will write to. media_thumb_dir = dump_dir + Media._thumb_dir podcast_thumb_dir = dump_dir + Podcast._thumb_dir media_files_dir = dump_dir + 'media_files' # Initialize our default paths to backup default_images = ['news.jpg', 'newm.jpg', 'newl.jpg'] media_thumbs = [m_img_dir+os.sep+img for img in default_images] podcast_thumbs = [p_img_dir+os.sep+img for img in default_images] media_files = [] # Add the media thumbs and media files for media in DBSession.query(Media).all(): file_paths = [file_path(f) for f in media.files] media_files += [fp for fp in file_paths if fp] media_thumbs += thumb_paths(media).values() # Add the podcast thumbs for podcast in DBSession.query(Podcast).all(): podcast_thumbs += thumb_paths(podcast).values() # Ensure the necessary directories exist. assert os.path.isdir(dump_dir) for subdir in (media_thumb_dir, media_files_dir, podcast_thumb_dir): if not os.path.exists(subdir): os.mkdir(subdir) assert os.path.isdir(subdir) empty_dir(subdir) # Copy over all of the files: sources_dests = ( (media_thumbs, media_thumb_dir), (media_files, media_files_dir), (podcast_thumbs, podcast_thumb_dir), ) for sources, dest_dir in sources_dests: for src in sources: if DEBUG: print "Copying %s to %s%s" % (src, dest_dir, os.sep) shutil.copy2(src, dest_dir) return 0,'%d thumbnails and %d media files successfully backed up' %\ (len(media_thumbs) + len(podcast_thumbs), len(media_files))
def remove_unnecessary_files(): # Move all media files and thumbnail files into 'deleted' folder. # XXX: don't run if deleted_dir is not set! if not deleted_dir: return for media in DBSession.query(Media).all(): file_paths = thumb_paths(media).values() for f in media.files: file_paths.append(f.file_path) helpers.delete_files(file_paths, 'media') for podcast in DBSession.query(Podcast).all(): file_paths = thumb_paths(podcast).values() helpers.delete_files(file_paths, 'podcasts')
def save(self, id, slug, title, subtitle, author_name, author_email, description, details, feed, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.podcasts.Podcast` instance. Form handler the :meth:`edit` action and the :class:`~mediacore.forms.admin.podcasts.PodcastForm`. Redirects back to :meth:`edit` after successful editing and :meth:`index` after successful deletion. """ podcast = fetch_row(Podcast, id) if delete: file_paths = thumb_paths(podcast).values() DBSession.delete(podcast) DBSession.commit() helpers.delete_files(file_paths, Podcast._thumb_dir) redirect(action='index', id=None) if not slug: slug = title if slug != podcast.slug: podcast.slug = get_available_slug(Podcast, slug, podcast) podcast.title = title podcast.subtitle = subtitle podcast.author = Author(author_name, author_email) podcast.description = description podcast.copyright = details['copyright'] podcast.category = details['category'] podcast.itunes_url = feed['itunes_url'] podcast.feedburner_url = feed['feedburner_url'] podcast.explicit = { 'yes': True, 'clean': False }.get(details['explicit'], None) if id == 'new': DBSession.add(podcast) DBSession.flush() create_default_thumbs_for(podcast) redirect(action='edit', id=podcast.id)
def _delete_media(self, media): # FIXME: Ensure that if the first file is deleted from the file system, # then the second fails, the first file is deleted from the # and not not linking to a nonexistent file. # Delete every file from the storage engine for file in media.files: file.storage.delete(file.unique_id) # Remove this item from the DBSession so that the foreign key # ON DELETE CASCADE can take effect. DBSession.expunge(file) # Delete the media DBSession.delete(media) DBSession.flush() # Cleanup the thumbnails thumbs = thumb_paths(media).values() helpers.delete_files(thumbs, Media._thumb_dir)
def s3_delete_thumbs(item): """Delete the thumbnails associated with the given item. :param item: A 2-tuple with a subdir name and an ID. If given a ORM mapped class with _thumb_dir and id attributes, the info can be extracted automatically. :type item: ``tuple`` or mapped class instance """ # fallback to normal thumb handling if no S3 engine is enabled. storage = get_s3_storage() if not storage: return None bucket = storage.connect_to_bucket() for path in thumb_paths(item, exists=True).itervalues(): bucket.delete_key(path) if bucket.get_key(path): raise RuntimeError('Delete failed') return True
def save( self, id, slug, title, subtitle, author_name, author_email, description, details, feed, delete=None, **kwargs ): """Save changes or create a new :class:`~mediacore.model.podcasts.Podcast` instance. Form handler the :meth:`edit` action and the :class:`~mediacore.forms.admin.podcasts.PodcastForm`. Redirects back to :meth:`edit` after successful editing and :meth:`index` after successful deletion. """ podcast = fetch_row(Podcast, id) if delete: file_paths = thumb_paths(podcast).values() DBSession.delete(podcast) DBSession.commit() helpers.delete_files(file_paths, Podcast._thumb_dir) redirect(action="index", id=None) if not slug: slug = title if slug != podcast.slug: podcast.slug = get_available_slug(Podcast, slug, podcast) podcast.title = title podcast.subtitle = subtitle podcast.author = Author(author_name, author_email) podcast.description = description podcast.copyright = details["copyright"] podcast.category = details["category"] podcast.itunes_url = feed["itunes_url"] podcast.feedburner_url = feed["feedburner_url"] podcast.explicit = {"yes": True, "clean": False}.get(details["explicit"], None) if id == "new": DBSession.add(podcast) DBSession.flush() create_default_thumbs_for(podcast) redirect(action="edit", id=podcast.id)
def merge_stubs(self, orig_id, input_id, **kwargs): """Merge in a newly created media item. This is merges media that has just been created. It must have: 1. a non-default thumbnail, or 2. a file, or 3. a title, description, etc :param orig_id: Media ID to copy data to :type orig_id: ``int`` :param input_id: Media ID to source files, thumbs, etc from :type input_id: ``int`` :returns: JSON dict """ orig = fetch_row(Media, orig_id) input = fetch_row(Media, input_id) merged_files = [] # Merge in the file(s) from the input stub if input.slug.startswith('_stub_') and input.files: for file in input.files[:]: # XXX: The filename will still use the old ID file.media = orig merged_files.append(file) DBSession.delete(input) # The original is a file or thumb stub, copy in the new values elif orig.slug.startswith('_stub_') \ and not input.slug.startswith('_stub_'): DBSession.delete(input) DBSession.flush() orig.podcast = input.podcast orig.title = input.title orig.subtitle = input.subtitle orig.slug = input.slug orig.author = input.author orig.description = input.description orig.notes = input.notes orig.duration = input.duration orig.views = input.views orig.likes = input.likes orig.publish_on = input.publish_on orig.publish_until = input.publish_until orig.categories = input.categories orig.tags = input.tags orig.update_popularity() # Copy the input thumb over the default thumbnail elif input.slug.startswith('_stub_') \ and has_default_thumbs(orig) \ and not has_default_thumbs(input): for key, dst_path in thumb_paths(orig).iteritems(): src_path = thumb_path(input, key) # This will raise an OSError on Windows, but not *nix os.rename(src_path, dst_path) DBSession.delete(input) # Report an error else: return dict( success = False, message = u'No merge operation fits.', ) orig.update_status() status_form_xhtml = unicode(update_status_form.display( action=url_for(action='update_status', id=orig.id), media=orig)) file_xhtml = {} for file in merged_files: file_xhtml[file.id] = unicode(edit_file_form.display( action=url_for(action='edit_file', id=orig.id), file=file)) return dict( success = True, media_id = orig.id, title = orig.title, link = url_for(action='edit', id=orig.id), status_form = status_form_xhtml, file_forms = file_xhtml, )
def save(self, id, slug, title, author_name, author_email, description, notes, podcast, tags, categories, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.media.Media` instance. Form handler the :meth:`edit` action and the :class:`~mediacore.forms.admin.media.MediaForm`. Redirects back to :meth:`edit` after successful editing and :meth:`index` after successful deletion. """ media = fetch_row(Media, id) if delete: file_paths = thumb_paths(media).values() for f in media.files: file_paths.append(f.file_path) # Remove the file from the session so that SQLAlchemy doesn't # try to issue an UPDATE to set the MediaFile.media_id to None. # The database ON DELETE CASCADE handles everything for us. DBSession.expunge(f) DBSession.delete(media) DBSession.commit() helpers.delete_files(file_paths, Media._thumb_dir) redirect(action='index', id=None) if not slug: slug = title elif slug.startswith('_stub_'): slug = slug[len('_stub_'):] if slug != media.slug: media.slug = get_available_slug(Media, slug, media) media.title = title media.author = Author(author_name, author_email) media.description = description media.notes = notes media.podcast_id = podcast media.set_tags(tags) media.set_categories(categories) media.update_status() DBSession.add(media) DBSession.flush() if id == 'new': create_default_thumbs_for(media) if request.is_xhr: status_form_xhtml = unicode(update_status_form.display( action=url_for(action='update_status', id=media.id), media=media)) return dict( media_id = media.id, values = {'slug': slug}, link = url_for(action='edit', id=media.id), status_form = status_form_xhtml, ) else: redirect(action='edit', id=media.id)