video_privacy_enhancer.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """
  2. Video Privacy Enhancer
  3. --------------------------
  4. Authored by Jacob Levernier, 2014
  5. Released under the GNU AGPLv3
  6. For more information on this plugin, please see the attached Readme.md file.
  7. """
  8. """
  9. SETTINGS
  10. """
  11. # Do not use a leading or trailing slash below (e.g., use "images/video-thumbnails"):
  12. output_directory_for_thumbnails = "images/video-thumbnails"
  13. """
  14. In order for this plugin to work optimally, you need to do just a few things:
  15. 1. Enable the plugn in pelicanconf.py (see http://docs.getpelican.com/en/3.3.0/plugins.html for documentation):
  16. PLUGIN_PATH = "/pelican-plugins"
  17. PLUGINS = ["video_privacy_enhancer"]
  18. 2a. If necessary, install jQuery on your site (See https://stackoverflow.com/questions/1458349/installing-jquery -- the jQuery base file should go into your Pelican themes 'static' directory)
  19. 2b. Copy the jQuery file in this folder into, for example, your_theme_folder/static/video_privacy_enhancer_jQuery.js, and add a line like this to the <head></head> element of your website's base.html (or equivalent) template:
  20. `<script src="{{ SITEURL }}/theme/video_privacy_enhancer_jquery.js"></script> <!--Load jQuery functions for the Video Privacy Enhancer Pelican plugin -->`
  21. 3. Choose a default video embed size and add corresponding CSS to your theme's CSS file:
  22. Youtube allows the following sizes in its embed GUI (as of this writing, in March 2014). I recommend choosing one, and then having the iframe for the actual video embed match it (so that it's a seamless transition). This can be handled with CSS in both cases, so I haven't hard-coded it here:
  23. 1280 W x 720 H
  24. 853 W x 480 H
  25. 640 W x 360 H
  26. 560 W x 315 H
  27. Here's an example to add to your CSS file:
  28. ```
  29. /* For use with the video-privacy-enhancer Pelican plugin */
  30. img.video-embed-dummy-image.
  31. iframe.embedded_youtube_video {
  32. width: 843px;
  33. max-height: 480px;
  34. /* Center the element on the screen */
  35. display: block;
  36. margin-top: 2em;
  37. margin-bottom: 2em;
  38. margin-left: auto;
  39. margin-right: auto;
  40. }
  41. iframe.embedded_youtube_video {
  42. width: 843px;
  43. height: 480px;
  44. }
  45. ```
  46. """
  47. """
  48. END SETTINGS
  49. """
  50. from pelican import signals # For making this plugin work with Pelican.
  51. import os.path # For checking whether files are present in the filesystem.
  52. import re # For using regular expressions.
  53. import urllib # For downloading the video thumbnails.
  54. import logging
  55. logger = logging.getLogger(__name__) # For using logger.debug() to log errors or other notes.
  56. # A function to check whtether output_directory_for_thumbnails (a variable set above in the SETTINGS section) exists. If it doesn't exist, we'll create it.
  57. def check_for_thumbnail_directory(pelican_output_path):
  58. # Per http://stackoverflow.com/a/84173, check if a file exists. isfile() works on files, and exists() works on files and directories.
  59. try:
  60. if not os.path.exists(pelican_output_path + "/" + output_directory_for_thumbnails): # If the directory doesn't exist already...
  61. os.makedirs(pelican_output_path + "/" + output_directory_for_thumbnails) # Create the directory to hold the video thumbnails.
  62. return True
  63. except:
  64. print logger.debug("Error in checking if thumbnail folder exists and making the directory if it doesn't.") # In case something goes wrong.
  65. return False
  66. # A function to download the video thumbnail from YouTube (currently the only supported video platform):
  67. def download_thumbnail(video_id_from_shortcode, pelican_output_path):
  68. # Check if the thumbnail directory exists already:
  69. check_for_thumbnail_directory(pelican_output_path)
  70. # Check if the thumbnail for this video exists already (if it's been previously downloaded). If it doesn't, download it:
  71. if not os.path.exists(pelican_output_path + "/" + output_directory_for_thumbnails + "/" + video_id_from_shortcode + ".jpg"): # If the thumbnail doesn't already exist...
  72. urllib.urlretrieve("https://img.youtube.com/vi/" + video_id_from_shortcode + "/0.jpg", pelican_output_path + "/" + output_directory_for_thumbnails + "/" + video_id_from_shortcode + ".jpg") # Download the thumbnail. This follows the instructions at http://www.reelseo.com/youtube-thumbnail-image/ for downloading YouTube thumbnail images.
  73. # A function to read through each page and post as it comes through from Pelican, find all instances of `!youtube(...)`, and change it into an HTML <img> element with the video thumbnail.
  74. def process_youtube_shortcodes(data_passed_from_pelican):
  75. if data_passed_from_pelican._content: # If the item passed from Pelican has a "content" attribute (i.e., if it's not an image file or something else like that). NOTE: data_passed_from_pelican.content (without an underscore in front of 'content') seems to be read-only, whereas data_passed_from_pelican._content is able to be overwritten. This is somewhat explained in an IRC log from 2013-02-03 from user alexis to user webdesignhero_ at https://botbot.me/freenode/pelican/2013-02-01/?tz=America/Los_Angeles.
  76. full_content_of_page_or_post = data_passed_from_pelican._content
  77. else:
  78. return # Exit the function, essentially passing over the (non-text) file.
  79. all_instances_of_the_youtube_shortcode = re.findall('\!youtube.*?\)', full_content_of_page_or_post) # Use a regular expression to find every instance of '!youtube' followed by anything up to the first matching ')'.
  80. if(len(all_instances_of_the_youtube_shortcode) > 0): # If the article/page HAS any shortcodes, go on. Otherwise, don't (to do so would inadvertantly wipe out the output content for that article/page).
  81. replace_shortcode_in_text = "" # This just gives this an initial value before going into the loop below.
  82. # Go through each shortcode instance that we found above, and parse it:
  83. for youtube_shortcode_to_parse in all_instances_of_the_youtube_shortcode:
  84. video_id_from_shortcode = re.findall('(?<=youtube\().*?(?=\))', youtube_shortcode_to_parse)[0] # Get what's inside of the parentheses in '!youtube(...).'
  85. # print "Video ID is " + video_id_from_shortcode # Good for debugging purposes.
  86. # Use the Pelican pelicanconf.py settings:
  87. pelican_output_path = data_passed_from_pelican.settings['OUTPUT_PATH']
  88. pelican_site_url = data_passed_from_pelican.settings['SITEURL']
  89. # Download the video thumbnail if it's not already on the filesystem:
  90. download_thumbnail(video_id_from_shortcode, pelican_output_path)
  91. # Replace '!youtube(...)' with '<img>...</img>'. Note that the <img> is given a class that the jQuery file mentioned at the top of this file will watch over. Any time an image with that class is clicked, the jQuery function will trigger and turn it into the full video embed.
  92. replace_shortcode_in_text = re.sub(r'\!youtube\(' + video_id_from_shortcode + '\)', r'<img class="youtube-embed-dummy-image" id="' + video_id_from_shortcode + '" src="' + pelican_site_url + '/' + output_directory_for_thumbnails + '/' + video_id_from_shortcode + '.jpg" alt="Embedded Video - Click to view" title="Embedded Video - Click to view"></img>', full_content_of_page_or_post)
  93. # Replace the content of the page or post with our now-updated content (having gone through all instances of the !youtube() shortcode and updated them all, exiting the loop above.
  94. data_passed_from_pelican._content = replace_shortcode_in_text
  95. # Make Pelican work (see http://docs.getpelican.com/en/3.3.0/plugins.html#how-to-create-plugins):
  96. def register():
  97. signals.content_object_init.connect(process_youtube_shortcodes)