media_archive.module 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <?php
  2. /**
  3. * @file media_archive/media_archive.module
  4. *
  5. * Media: Archive provides a stream wrapper and formatters for videos provided
  6. * by Archive, available at http://archive.org/.
  7. *
  8. * @TODO:
  9. * Tie in Archive API.
  10. * Allow editors to search for videos to display on the browser.
  11. * Allow editors to put in a archive username to display on the browser.
  12. * Allow editors to log in w/ their credentials.
  13. * Allow editors to upload videos to Archive.
  14. */
  15. // A registry of variable_get defaults.
  16. include_once('includes/media_archive.variables.inc');
  17. /**
  18. * Create stream wrapper for Archive videos.
  19. */
  20. function media_archive_stream_wrappers() {
  21. return array(
  22. 'archive' => array(
  23. 'name' => t('Archive videos'),
  24. 'class' => 'MediaArchiveStreamWrapper',
  25. 'description' => t('Videos provided by Archive.'),
  26. 'type' => STREAM_WRAPPERS_READ_VISIBLE,
  27. ),
  28. );
  29. }
  30. function media_archive_media_format_form_prepare_alter(&$form, &$form_state, $media) {
  31. $settings = array('autosubmit' => ($media->type == "video"));
  32. drupal_add_js(array('media_format_form' => $settings), 'setting');
  33. }
  34. /**
  35. * Implements hook_theme().
  36. */
  37. function media_archive_theme($existing, $type, $theme, $path) {
  38. return array(
  39. 'media_archive_preview_style' => array(
  40. 'variables' => array('style_name' => NULL),
  41. 'file' => 'media_archive.theme.inc',
  42. 'path' => $path . '/includes/themes',
  43. ),
  44. 'media_archive_field_formatter_styles' => array(
  45. 'variables' => array('element' => NULL, 'style' => NULL),
  46. 'file' => 'media_archive.theme.inc',
  47. 'path' => $path . '/includes/themes',
  48. ),
  49. 'media_archive_video' => array(
  50. 'variables' => array('uri' => NULL, 'width' => NULL, 'height' => NULL, 'autoplay' => NULL, 'fullscreen' => NULL),
  51. 'file' => 'media_archive.theme.inc',
  52. 'path' => $path . '/includes/themes',
  53. 'template' => 'media-archive-video',
  54. ),
  55. 'media_archive_embed' => array(
  56. 'variables' => array('style_name' => NULL, 'uri' => NULL, 'alt' => NULL, 'title' => NULL),
  57. 'file' => 'media_archive.theme.inc',
  58. 'path' => $path . '/includes/themes',
  59. ),
  60. 'media_archive_styles' => array(
  61. 'variables' => array('element' => NULL, 'style' => NULL),
  62. 'file' => 'media_archive.theme.inc',
  63. 'path' => $path . '/includes/themes',
  64. ),
  65. );
  66. }
  67. /**
  68. * Implementation of Styles module hook_styles_register().
  69. */
  70. function media_archive_styles_register() {
  71. return array(
  72. 'MediaArchiveStyles' => array(
  73. 'field_types' => 'file',
  74. 'name' => t('MediaArchive'),
  75. 'description' => t('Media Archive styles.'),
  76. 'path' => drupal_get_path('module', 'media_archive') .'/includes',
  77. 'file' => 'media_archive.styles.inc',
  78. ),
  79. );
  80. }
  81. /**
  82. * Implements hook_styles_containers(). (Deprecated in version 2)
  83. */
  84. function media_archive_styles_containers() {
  85. return array(
  86. 'file' => array(
  87. 'containers' => array(
  88. 'media_archive' => array(
  89. 'label' => t('Archive Styles'),
  90. 'data' => array(
  91. 'streams' => array(
  92. 'archive',
  93. ),
  94. 'mimetypes' => array(
  95. 'video/archive',
  96. ),
  97. ),
  98. 'weight' => 0,
  99. 'filter callback' => 'media_archive_formatter_filter',
  100. 'themes' => array(
  101. 'field_formatter_styles' => 'media_archive_field_formatter_styles',
  102. 'styles' => 'media_archive_styles',
  103. 'preview' => 'media_archive_preview_style',
  104. ),
  105. 'description' => t('Archive Styles will display embedded Archive videos and thumbnails to your choosing, such as by resizing, setting colors, and autoplay. You can !manage.', array('!manage' => l(t('manage your Archive styles here'), 'admin/config/media/media-archive-styles'))),
  106. ),
  107. ),
  108. ),
  109. );
  110. }
  111. function media_archive_formatter_filter($variables) {
  112. if (isset($variables['object'])) {
  113. $object = $variables['object'];
  114. return (file_uri_scheme($object->uri) == 'archive') && ($object->filemime == 'video/archive');
  115. }
  116. }
  117. /**
  118. * Implementation of the File Styles module's hook_file_styles_filter().
  119. */
  120. function media_archive_file_styles_filter($object) {
  121. if ((file_uri_scheme($object->uri) == 'archive') && ($object->filemime == 'video/archive')) {
  122. return 'media_archive';
  123. }
  124. }
  125. /**
  126. * Implements hook_styles_styles().
  127. */
  128. function media_archive_styles_styles() {
  129. $styles = array(
  130. 'file' => array(
  131. 'containers' => array(
  132. 'media_archive' => array(
  133. 'styles' => array(
  134. 'archive_thumbnail' => array(
  135. 'name' => 'archive_thumbnail',
  136. 'effects' => array(
  137. array('label' => t('Thumbnail'), 'name' => 'thumbnail', 'data' => array('thumbnail' => 1)),
  138. array('label' => t('Resize'), 'name' => 'resize', 'data' => array('width' => 100, 'height' => 75)),
  139. ),
  140. ),
  141. 'archive_preview' => array(
  142. 'name' => 'archive_preview',
  143. 'effects' => array(
  144. array('label' => t('Autoplay'), 'name' => 'autoplay', 'data' => array('autoplay' => 1)),
  145. array('label' => t('Resize'), 'name' => 'resize', 'data' => array('width' => 220, 'height' => 165)),
  146. ),
  147. ),
  148. 'archive_full' => array(
  149. 'name' => 'archive_full',
  150. 'effects' => array(
  151. array('label' => t('Autoplay'), 'name' => 'autoplay', 'data' => array('autoplay' => 0)),
  152. array('label' => t('Resize'), 'name' => 'resize', 'data' => array('width' => 640, 'height' => 480)),
  153. array('label' => t('Full screen'), 'name' => 'fullscreen', 'data' => array('fullscreen' => 1)),
  154. ),
  155. ),
  156. ),
  157. ),
  158. ),
  159. ),
  160. );
  161. // Allow any image style to be applied to the thumbnail.
  162. foreach (image_styles() as $style_name => $image_style) {
  163. $styles['file']['containers']['media_archive']['styles']['archive_thumbnail_' . $style_name] = array(
  164. 'name' => 'archive_thumbnail_' . $style_name,
  165. 'image_style' => $style_name,
  166. 'effects' => array(
  167. array('label' => t('Thumbnail'), 'name' => 'thumbnail', 'data' => array('thumbnail' => 1)),
  168. ),
  169. );
  170. }
  171. return $styles;
  172. }
  173. /**
  174. * Implements hook_styles_presets().
  175. */
  176. function media_archive_styles_presets() {
  177. $presets = array(
  178. 'file' => array(
  179. 'square_thumbnail' => array(
  180. 'media_archive' => array(
  181. 'archive_thumbnail_square_thumbnail',
  182. ),
  183. ),
  184. 'thumbnail' => array(
  185. 'media_archive' => array(
  186. 'archive_thumbnail',
  187. ),
  188. ),
  189. 'small' => array(
  190. 'media_archive' => array(
  191. 'archive_preview',
  192. ),
  193. ),
  194. 'large' => array(
  195. 'media_archive' => array(
  196. 'archive_full',
  197. ),
  198. ),
  199. 'original' => array(
  200. 'media_archive' => array(
  201. 'archive_full',
  202. ),
  203. ),
  204. ),
  205. );
  206. return $presets;
  207. }
  208. /**
  209. * Implements hook_media_parse().
  210. *
  211. * @todo: this might be deprecated now that we have media_internet,
  212. * but the hook is still being called in a couple places in media.
  213. */
  214. function media_archive_media_parse($url, $options = array()) {
  215. $scheme = 'archive://';
  216. preg_match('@archive\.org/details/([^"\& ]+)@i', $url, $matches);
  217. if (isset($matches[1])) {
  218. $org = media_archive_embedcode_lookup($matches[1]);
  219. return file_stream_wrapper_uri_normalize($scheme . 'v/' . $matches[1] . '/org/' . $org);
  220. }
  221. // @TODO: Validate for malformed archive urls.
  222. }
  223. /**
  224. * Implements hook_media_internet_providers();
  225. */
  226. function media_archive_media_internet_providers() {
  227. $path = drupal_get_path('module', 'media_archive');
  228. return array(
  229. 'MediaInternetArchiveHandler' => array(
  230. 'title' => 'archive',
  231. 'image' => $path . '/images/stream-archive.png'
  232. ),
  233. );
  234. }
  235. class MediaInternetArchiveHandler extends MediaInternetBaseHandler {
  236. public function claim($embedCode) {
  237. if (media_archive_media_parse($embedCode)) {
  238. return TRUE;
  239. }
  240. }
  241. public function validate() {
  242. // @todo Media module currently fails when two files try to have the same
  243. // URI, so catch that in the validation step. Some day, it would be nice
  244. // to allow it, however. See http://drupal.org/node/952422.
  245. $uri = media_archive_media_parse($this->embedCode);
  246. $existing_files = file_load_multiple(array(), array('uri' => $uri));
  247. if (count($existing_files)) {
  248. throw new MediaInternetValidationException(t('You have entered a URL for a video that is already in your library.'));
  249. }
  250. }
  251. public function save() {
  252. $file = $this->getFileObject();
  253. file_save($file);
  254. return $file;
  255. }
  256. public function getFileObject() {
  257. $uri = media_archive_media_parse($this->embedCode);
  258. //@todo: this is terribly broken in some ways because the function is really
  259. // made for local files which are 'real'
  260. return file_uri_to_object($uri);
  261. }
  262. /**
  263. * Returns information about the media. See http://video.search.yahoo.com/mrss.
  264. *
  265. * @return
  266. * If ATOM+MRSS information is available, a SimpleXML element containing
  267. * ATOM and MRSS elements, as per those respective specifications.
  268. *
  269. * @todo Would be better for the return value to be an array rather than a
  270. * SimpleXML element, but media_retrieve_xml() needs to be upgraded to
  271. * handle namespaces first.
  272. */
  273. //http://archive.org/file/4035623?skin=rss
  274. public function getMRSS() {
  275. $uri = media_archive_media_parse($this->embedCode);
  276. $video_id = arg(1, file_uri_target($uri));
  277. $rss_url = url('http://gdata.archive.org/feeds/api/videos/' . $video_id, array('query' => array('v' => '2')));
  278. // @todo Use media_retrieve_xml() once it's upgraded to include elements
  279. // from all namespaces, not just the document default namespace.
  280. $entry = simplexml_load_file($rss_url);
  281. return $entry;
  282. }
  283. /**
  284. * Returns information about the media. See http://www.oembed.com/.
  285. *
  286. * @return
  287. * If oEmbed information is available, an array containing 'title', 'type',
  288. * 'url', and other information as specified by the oEmbed standard.
  289. * Otherwise, NULL.
  290. */
  291. //http://archive.org/oembed/?url=http://archive.org/file/12345
  292. public function getOEmbed() {
  293. $uri = media_archive_media_parse($this->embedCode);
  294. $external_url = drupal_realpath($uri);
  295. $oembed_url = url('http://archive.org/oembed', array('query' => array('url' => $external_url, 'format' => 'json')));
  296. $response = drupal_http_request($oembed_url);
  297. if (!isset($response->error)) {
  298. return drupal_json_decode($response->data);
  299. }
  300. }
  301. }
  302. function media_archive_embedcode_lookup($video_id) {
  303. //http://www.archive.org/download/bavc-77620-dominotheory/bavc-77620-dominotheory_files.xml
  304. //<original>Domino_Theory.mpeg</original>
  305. // I hate this, but after reading http://data.agaric.com/node/2378 I'm
  306. // begining to think there isn't an easier way
  307. // if there isn't a better way, this needs to be done once and stored
  308. $url = 'http://www.archive.org/download/' . $video_id . '/' . $video_id;
  309. $rss_source = $url . '_files.xml';
  310. $rss = file_get_contents($rss_source);
  311. preg_match('/<original>(.+)<\/original>/', $rss, $matches);
  312. if (isset($matches[1])) {
  313. $info = pathinfo($matches[1]);
  314. $file_name = basename($matches[1],'.'.$info['extension']);
  315. return $file_name;
  316. }
  317. }