From 15c6d97b3ccc535deec07521cfc75edad99013b3 Mon Sep 17 00:00:00 2001 From: emilye Date: Thu, 14 Sep 2017 16:15:17 -0400 Subject: [PATCH] initial commit to cma --- LICENSE.txt | 339 ++++++++++ css/telvue.css | 3 + modules/feeds_telvue/FeedsTelvueParser.inc | 229 +++++++ modules/feeds_telvue/feeds_telvue.info | 19 + modules/feeds_telvue/feeds_telvue.install | 29 + modules/feeds_telvue/feeds_telvue.module | 35 + modules/telvue_blocks/css/telvue.css | 3 + modules/telvue_blocks/telvue_blocks.info | 15 + modules/telvue_blocks/telvue_blocks.module | 280 ++++++++ .../templates/telvue-blocks-next.tpl.php | 6 + .../telvue-blocks-now-and-next.tpl.php | 9 + .../telvue-blocks-playing-now.tpl.php | 6 + modules/telvue_push/telvue_push.info | 23 + modules/telvue_push/telvue_push.module | 607 ++++++++++++++++++ .../telvue_show_fields.features.field.inc | 217 +++++++ .../telvue_show_fields.info | 19 + .../telvue_show_fields.module | 5 + telvue.info | 16 + telvue.install | 11 + telvue.module | 246 +++++++ templates/telvue-playing-now.tpl.php | 3 + templates/telvue-show-next-airing.tpl.php | 3 + .../telvue-show-now-and-next-airing.tpl.php | 5 + 23 files changed, 2128 insertions(+) create mode 100755 LICENSE.txt create mode 100644 css/telvue.css create mode 100644 modules/feeds_telvue/FeedsTelvueParser.inc create mode 100644 modules/feeds_telvue/feeds_telvue.info create mode 100644 modules/feeds_telvue/feeds_telvue.install create mode 100644 modules/feeds_telvue/feeds_telvue.module create mode 100644 modules/telvue_blocks/css/telvue.css create mode 100644 modules/telvue_blocks/telvue_blocks.info create mode 100644 modules/telvue_blocks/telvue_blocks.module create mode 100644 modules/telvue_blocks/templates/telvue-blocks-next.tpl.php create mode 100644 modules/telvue_blocks/templates/telvue-blocks-now-and-next.tpl.php create mode 100644 modules/telvue_blocks/templates/telvue-blocks-playing-now.tpl.php create mode 100644 modules/telvue_push/telvue_push.info create mode 100644 modules/telvue_push/telvue_push.module create mode 100644 modules/telvue_show_fields/telvue_show_fields.features.field.inc create mode 100644 modules/telvue_show_fields/telvue_show_fields.info create mode 100644 modules/telvue_show_fields/telvue_show_fields.module create mode 100644 telvue.info create mode 100644 telvue.install create mode 100644 telvue.module create mode 100644 templates/telvue-playing-now.tpl.php create mode 100644 templates/telvue-show-next-airing.tpl.php create mode 100644 templates/telvue-show-now-and-next-airing.tpl.php diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100755 index 0000000..d159169 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/css/telvue.css b/css/telvue.css new file mode 100644 index 0000000..c66fb97 --- /dev/null +++ b/css/telvue.css @@ -0,0 +1,3 @@ +.now-next-airing { + text-align: center; +} \ No newline at end of file diff --git a/modules/feeds_telvue/FeedsTelvueParser.inc b/modules/feeds_telvue/FeedsTelvueParser.inc new file mode 100644 index 0000000..61569a5 --- /dev/null +++ b/modules/feeds_telvue/FeedsTelvueParser.inc @@ -0,0 +1,229 @@ +getRaw(); + + $result = new FeedsParserResult(); + + /** + * @see common_syndication_parser_parse() + */ + if (!defined('LIBXML_VERSION') || (version_compare(phpversion(), '5.1.0', '<'))) { + @$sxml = simplexml_load_string($mediarss_feed, NULL); + } + else { + @$sxml = simplexml_load_string($mediarss_feed, NULL, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOCDATA); + } + + // Got a malformed XML. + if ($sxml === FALSE || is_null($sxml)) { + throw new Exception(t('FeedsTelvueParser: Malformed XML source.')); + } + + if ($this->isRssFeed($sxml)) { + $result = $this->parseRss20($sxml, $source, $fetcher_result); + } + else { + throw new Exception(t('FeedsTelvueParser: Unknown type of feed.')); + } + return $result; + } + + /** + * Check if given feed object is a RSS feed. + * + * @param SimpleXMLElement $sxml + * + * @return boolen + * TRUE if given SimpleXML object is RSS feed or FALSE + */ + protected function isRssFeed(SimpleXMLElement $sxml) { + return $sxml->getName() == 'rss'; + } + + /** + * Add the extra mapping sources provided by this parser. + */ + public function getMappingSources() { + return parent::getMappingSources() + array( + 'guid' => array( + 'name' => t('GUID'), + ), + 'link' => array( + 'name' => t('Link'), + ), + 'title' => array( + 'name' => t('Title'), + 'description' => t('Title.'), + ), + 'author' => array( + 'name' => t('Author'), + 'description' => t('Author or uploader of the video.'), + ), + 'published' => array( + 'name' => t('Published'), + ), + 'description' => array( + 'name' => t('Description'), + ), + 'tags' => array( + 'name' => t('Tags'), + 'description' => t('This can be imported directly with Taxonomy "tags" vocabularies.'), + ), + + + // http://www.telvue.com/support/product-documentation/princeton-server-api-docs/schedule-methods/get-channel-schedule-as-rss-rest/ + 'channel' => array( + 'name' => t('channel'), + ), + 'psg_eventid' => array( + 'name' => t('eventId'), + ), + 'psg_duration' => array( + 'name' => t('duration'), + ), + 'psg_end_datetime' => array( + 'name' => t('end_datetime'), + ), + 'psg_programcode' => array( + 'name' => t('programCode'), + ), + 'psg_episode' => array( + 'name' => t('episode'), + ), + 'psg_episodecode' => array( + 'name' => t('episodeCode'), + ), + 'psg_thumbnail' => array( + 'name' => t('thumbnail'), + ), + + ); + } + + + + /** + * Parse RSS 2.0 feed + * + * @param SimpleXMLElement $sxml + * @param FeedsFetcherResult $fetcher_result + * @param FeedsSource $source + */ + private function parseRss20(SimpleXMLElement $sxml, FeedsSource $source, FeedsFetcherResult $fetcher_result) { + + // XML was parsed successfully, so we can begin to process items + $result = new FeedsParserResult(); + $fetcher_result->title = (string) $sxml->channel->title; + $fetcher_result->description = (string) $sxml->channel->description; + $fetcher_result->link = (string) $sxml->channel->link; + $feed_title = (string) $sxml->channel->title; + + $namespaces = $sxml->getNamespaces(true); + + foreach ($sxml->xpath('//item') as $entry) { + + // Get nodes in media: namespace for media information + $psg = $entry->children($namespaces['psg']); + + $start_parts = explode(' -', $entry->pubDate); + $end_parts = explode(' -', $psg->end_datetime[0]); + + //shift + $hours = $start_parts[1]/100; + $shift = 60*60*$hours; + + $start = strtotime($start_parts[0]) - $shift; + $end = strtotime($end_parts[0]) - $shift; + + //$start = strtotime($start_parts[0]); + //$end = strtotime($end_parts[0]); + + $item = array( + 'guid' => (string) $entry->guid, + 'link' => (string) $entry->link, + 'title' => html_entity_decode((string) $entry->title), + 'author' => (string) $entry->author, + 'description' => html_entity_decode((string) $entry->description), + // $media object doesn't exist. + //'tags' => explode(',', (string) $media->group->keywords), + 'published' => (string) $start, + 'channel' => (string) $feed_title, + 'psg_eventid' => (string) $psg->eventId[0], + 'psg_duration' => (string) $psg->duration[0], + 'psg_end_datetime' => $end, + 'psg_programcode' => (string) $psg->programcode[0], + 'psg_episode' => (string) $psg->episode[0], + 'psg_episodecode' => (string) $psg->episodecode[0], + 'psg_thumbnail' => (string) $psg->thumbnail[0], + + ); + + // Populate the FeedsFetcherResult object with the parsed results. + $result->items[] = $item; + } + + return $result; + } + + /** + * Display seconds as HH:MM:SS, with leading 0's. + * + * @param $seconds + * The number of seconds to display. + */ + public function secsToTime($seconds) { + // Number of seconds in an hour. + $unith = 3600; + // Number of seconds in a minute. + $unitm = 60; + + // '/' given value by num sec in hour... output = HOURS + $hh = intval($seconds / $unith); + + // Multiply number of hours by seconds, then subtract from given value. + // Output = REMAINING seconds. + $ss_remaining = ($seconds - ($hh * 3600)); + + // Take remaining seconds and divide by seconds in a min... output = MINS. + $mm = intval($ss_remaining / $unitm); + // Multiply number of mins by seconds, then subtract from remaining seconds. + // Output = REMAINING seconds. + $ss = ($ss_remaining - ($mm * 60)); + + $output = ''; + + // If we have any hours, then prepend that to our output. + if ($hh) { + $output .= "$hh:"; + } + + // Create a safe-for-output MM:SS. + $output .= sprintf($hh ? "%02d:%02d" : "%d:%02d", $mm, $ss); + + return $output; + } +} + + diff --git a/modules/feeds_telvue/feeds_telvue.info b/modules/feeds_telvue/feeds_telvue.info new file mode 100644 index 0000000..288f544 --- /dev/null +++ b/modules/feeds_telvue/feeds_telvue.info @@ -0,0 +1,19 @@ +; Basic information +name = Feeds: Telvue Schedule +description = Defines psg elements found in the Telvue's Schedule feed so they can be mapped by Feeds. +core = 7.x +package = Feeds +dependencies[] = "feeds" + +; Files +files[] = feeds_telvue.install +files[] = feeds_telvue.module +files[] = FeedsTelvueParser.inc + + +; Information added by Drupal.org packaging script on 2014-04-29 +version = "7.x-1.0-alpha5" +core = "7.x" +project = "telvue" +datestamp = "1398793128" + diff --git a/modules/feeds_telvue/feeds_telvue.install b/modules/feeds_telvue/feeds_telvue.install new file mode 100644 index 0000000..53c04b1 --- /dev/null +++ b/modules/feeds_telvue/feeds_telvue.install @@ -0,0 +1,29 @@ + 1); + } +} + +/** + * Implements hook_feeds_plugins(). + */ +function feeds_telvue_feeds_plugins() { + $info = array(); + $info['FeedsTelvueParser'] = array( + 'name' => 'Telvue Schedule RSS parser', + 'description' => 'Parse Schedule feeds from Tevlue playback server.', + 'help' => 'Use PHP SimpleXML parser to parse Telvue feed for custom psg elements.', + 'handler' => array( + 'parent' => 'FeedsParser', + 'class' => 'FeedsTelvueParser', + 'file' => 'FeedsTelvueParser.inc', + 'path' => drupal_get_path('module', 'feeds_telvue'), + ), + ); + return $info; +} diff --git a/modules/telvue_blocks/css/telvue.css b/modules/telvue_blocks/css/telvue.css new file mode 100644 index 0000000..c66fb97 --- /dev/null +++ b/modules/telvue_blocks/css/telvue.css @@ -0,0 +1,3 @@ +.now-next-airing { + text-align: center; +} \ No newline at end of file diff --git a/modules/telvue_blocks/telvue_blocks.info b/modules/telvue_blocks/telvue_blocks.info new file mode 100644 index 0000000..94fb038 --- /dev/null +++ b/modules/telvue_blocks/telvue_blocks.info @@ -0,0 +1,15 @@ +name = Telvue Blocks +package = Community Media +description = "Defines Blocks to Display Now Playing, Playing Next, and Now and Next blocks populated from a Telvue." +core = 7.x +dependencies[] = "telvue" + +configure = admin/structure/block + + +; Information added by Drupal.org packaging script on 2014-04-29 +version = "7.x-1.0-alpha5" +core = "7.x" +project = "telvue" +datestamp = "1398793128" + diff --git a/modules/telvue_blocks/telvue_blocks.module b/modules/telvue_blocks/telvue_blocks.module new file mode 100644 index 0000000..5100b4c --- /dev/null +++ b/modules/telvue_blocks/telvue_blocks.module @@ -0,0 +1,280 @@ + t('Telvue: Now Playing'), + 'status' => FALSE, + 'region' => 'sidebar_first', + 'weight' => -99, + 'visibility' => 1, + 'pages' => '', + ); + + $blocks['telvue_blocks_next'] = array( + 'info' => t('Telvue: Next Airing'), + 'status' => FALSE, + 'region' => 'sidebar_first', + 'weight' => 0, + 'visibility' => 1, + 'pages' => 'node/*', + ); + + $blocks['telvue_blocks_now_and_next'] = array( + 'info' => t('Telvue: Now Playing and Next'), + 'status' => FALSE, + 'region' => 'sidebar_first', + 'weight' => 0, + 'visibility' => 1, + 'pages' => '', + ); + + return $blocks; +} + +/** + * Implements hook_block_configure(). + * + * This hook declares configuration options for blocks provided by this module. + */ +function telvue_blocks_block_configure($delta = '') { + // The $delta parameter tells us which block is being configured. + // In this example, we'll allow the administrator to customize + // the text of the 'configurable text string' block defined in this module. + + $form = array(); + if ($delta == 'telvue_blocks_playing_now') { + // All we need to provide is the specific configuration options for our + // block. Drupal will take care of the standard block configuration options + // (block title, page visibility, etc.) and the save button. + $form['telvue_blocks_string'] = array( + '#type' => 'textfield', + '#title' => t('Block contents'), + '#size' => 60, + '#description' => t('This text will appear in the example block.'), + '#default_value' => variable_get('telvue_blocks_string', t('Some example content.')), + ); + } + return $form; +} + +/** + * Implements hook_block_save(). + * + * This hook declares how the configured options for a block + * provided by this module are saved. + */ +function telvue_blocks_block_save($delta = '', $edit = array()) { + // We need to save settings from the configuration form. + // We need to check $delta to make sure we are saving the right block. + if ($delta == 'telvue_blocks_playing_now') { + // Have Drupal save the string to the database. + variable_set('telvue_blocks_string', $edit['telvue_blocks_string']); + } + return; +} + +/** + * Implements hook_block_view(). + * + */ +function telvue_blocks_block_view($delta = '') { + switch ($delta) { + case 'telvue_blocks_playing_now': + $block['subject'] = t('Telvue: Now Playing'); + $block['content'] = telvue_blocks_contents($delta); + break; + case 'telvue_blocks_next': + $block['subject'] = t('Telvue: Playing Next'); + $block['content'] = telvue_blocks_contents($delta); + break; + case 'telvue_blocks_now_and_next': + $block['subject'] = t('Tevlue: Now and Next'); + $block['content'] = telvue_blocks_contents($delta); + break; + } + return $block; +} + +/** + * A module-defined block content function. + */ +function telvue_blocks_contents($which_block) { + if (!variable_get('telvue_uri', '')) { + drupal_set_message('Telvue module must be configured before a Playing Now or Next block can be used.', 'error'); + return; + } + switch ($which_block) { + case 'telvue_blocks_playing_now': + + $feed = variable_get('telvue_uri', '') . '/xml/nowplaying'; + $show = telvue_blocks_get_playing_rss($feed); + + return theme('telvue_blocks_playing_now', array('show' => $show)); + + + case 'telvue_blocks_next': + + $feed = variable_get('telvue_uri', '') . '/xml/nextplaying'; + $show = telvue_blocks_get_playing_rss($feed); + + return theme('telvue_blocks_show_next', array('show' => $show)); + + + case 'telvue_blocks_now_and_next': + + drupal_add_css(drupal_get_path('module', 'telvue') . '/css/telvue.css'); + + $feed = variable_get('telvue_uri', '') . '/xml/nowplaying'; + $now = telvue_blocks_get_playing_rss($feed); + + $feed = variable_get('telvue_uri', '') . '/xml/nextplaying'; + $next = telvue_blocks_get_playing_rss($feed); + + return theme('telvue_blocks_now_and_next', array('now' => $now, 'next' => $next)); + } +} + +/* + * The following hooks can be used to alter blocks + * provided by your own or other modules. + */ + +/** + * Implements hook_block_list_alter(). + */ +function telvue_blocks_block_list_alter(&$blocks) { + // We are going to make the search block sticky on bottom of regions. For + // this example, we will modify the block list and append the search block at + // the end of the list, so even if the administrator configures the block to + // be on the top of the region, it will demote to bottom again. + foreach ($blocks as $bid => $block) { + if (($block->module == 'search') && ($block->delta == 'form')) { + // Remove the block from the list and append to the end. + unset($blocks[$bid]); + $blocks[$bid] = $block; + break; + } + } +} + +/** + * Implements hook_block_view_alter(). + * + */ +function telvue_blocks_block_view_alter(&$data, $block) { + // Verify the we have raw text content + if (!isset($data['content']) || !is_string($data['content'])) { + return; + } + + // If the content contains the string: 'magic string', uppercase the title. + if (strstr($data['content'], 'magic string')) { + $data['subject'] = isset($data['subject']) ? drupal_strtoupper($data['subject']) : ''; + } +} + +/** + * Returns Show as Array + */ +function telvue_blocks_get_playing_rss($feed) { + + if (variable_get('telvue_blocks_cache', 0)) { + if (($cache == cache_get($feed)) && !empty($cache->data)) { + return $cache->data; + } + } else { + + $rawFeed = file_get_contents($feed); + $xml = new SimpleXmlElement($rawFeed); + + foreach ($xml->channel->item as $item) { + + $show = array(); + $show['title'] = (string) $item->title; + + //IF TELVUE RETURNS NA + if ($show['title'] == 'NA') { + + $error = variable_get('telvue_connection_error', ''); + + //BECAUSE THE TELVUE DOESN'T RETURN ANYTHING OTHER THAN A TITLE + //WHEN NA, AN UNSET telvue_blocks_connection_error RETURNS NOTHING + $show['title'] = $error; + $show['cleantitle'] = $error; + $show['starttimestamp'] = NULL; + return $show; + } + + $show['link'] = (string) $item->link; + $show['description'] = (string) $item->description; + $show['pubDate'] = (string) $item->pubDate; + $show['guid'] = (string) $item->guid; + + //Clean up Title + $titleparts = explode(' - ', $show['title']); + $show['cleantitle'] = $titleparts[0]; + $show['starttimestamp'] = strtotime($titleparts[1]); + + //Multiple categories + foreach ($item->category as $category) { + $show['category'][] = (string) $category; + } + + //Telvue Specific Namespace Elements + // First get the base URI + $uriparts = explode('/xml/', $feed); + $dc = $item->children($uriparts[0] . '/psg_namespace/'); + + $show['eventId'] = (string) $dc->eventId; + $show['duration'] = (string) $dc->duration; + $show['elapsed'] = (string) $dc->elapsed; + $show['eventId'] = (string) $dc->eventId; + $show['thumbnail'] = (string) $dc->thumbnail; + + if ($show['duration']) { + $show['endtimestamp'] = ($show['starttimestamp'] + telvue_hms2sec($show['duration'])); + } else { + $show['endtimestamp'] = NULL; + } + } + + + if (variable_get('telvue_blocks_cache', 0)) { + //since the nextplaying feed doesn't include duration, $show['endtimestamp'] + // can't be calculated. Use the start since that will be in the future + if ($show['endtimestamp']){ + cache_set($feed, $show, 'cache', $show['endtimestamp']); + } else { + cache_set($feed, $show, 'cache', $show['starttimestamp']); + } + } + } + return $show; +} + +/** + * Implements hook_theme(). + * + */ +function telvue_blocks_theme() { + + return array( + 'telvue_blocks_playing_now' => array( + 'template' => 'templates/telvue-blocks-playing-now', + 'variables' => array('show' => NULL), + ), + 'telvue_blocks_next_' => array( + 'template' => 'templates/telvue-blocks-next', + 'variables' => array('show' => NULL), + ), + 'telvue_blocks_now_and_next' => array( + 'template' => 'templates/telvue-blocks-now-and-next', + 'variables' => array('now' => NULL, 'next' => NULL), + ), + ); +} diff --git a/modules/telvue_blocks/templates/telvue-blocks-next.tpl.php b/modules/telvue_blocks/templates/telvue-blocks-next.tpl.php new file mode 100644 index 0000000..1168f34 --- /dev/null +++ b/modules/telvue_blocks/templates/telvue-blocks-next.tpl.php @@ -0,0 +1,6 @@ +

'; + + -
+ + +
\ No newline at end of file diff --git a/modules/telvue_blocks/templates/telvue-blocks-now-and-next.tpl.php b/modules/telvue_blocks/templates/telvue-blocks-now-and-next.tpl.php new file mode 100644 index 0000000..e893bb8 --- /dev/null +++ b/modules/telvue_blocks/templates/telvue-blocks-now-and-next.tpl.php @@ -0,0 +1,9 @@ +

+ + -
+ + + +
Playing Next: + +
\ No newline at end of file diff --git a/modules/telvue_blocks/templates/telvue-blocks-playing-now.tpl.php b/modules/telvue_blocks/templates/telvue-blocks-playing-now.tpl.php new file mode 100644 index 0000000..302065a --- /dev/null +++ b/modules/telvue_blocks/templates/telvue-blocks-playing-now.tpl.php @@ -0,0 +1,6 @@ +

+ + -
+ + +
\ No newline at end of file diff --git a/modules/telvue_push/telvue_push.info b/modules/telvue_push/telvue_push.info new file mode 100644 index 0000000..0637e83 --- /dev/null +++ b/modules/telvue_push/telvue_push.info @@ -0,0 +1,23 @@ +name = Telvue Push +description = "Pushes Standard Metadata Fields to Telvue using Telvue API [PATCHED] by wluisi on 8/8/2015" +core = 7.x + +package = Community Media +project = Telvue + +dependencies[] = telvue +dependencies[] = password_field +dependencies[] = field_extract +dependencies[] = entity + +files[] = telvue_push.module + +configure = admin/config/system/telvue-push + + +; Information added by Drupal.org packaging script on 2014-04-29 +version = "7.x-1.0-alpha5" +core = "7.x" +project = "telvue" +datestamp = "1398793128" + diff --git a/modules/telvue_push/telvue_push.module b/modules/telvue_push/telvue_push.module new file mode 100644 index 0000000..7219742 --- /dev/null +++ b/modules/telvue_push/telvue_push.module @@ -0,0 +1,607 @@ + array( + 'title' => t('Push to Telvue'), + 'description' => t('Allows users to push Show metadata to Telvue with Save and Push button.'), + 'restrict access' => TRUE, + ), + ); + + return $permissions; +} + +/** + * Implementation of hook_menu(). + */ +function telvue_push_menu() { + $items = array(); + + // Standard Administration settings. + $items['admin/config/system/telvue-push'] = array( + 'title' => 'Telvue Push Configuration', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('telvue_push_admin_settings'), + 'access callback' => 'user_access', + 'access arguments' => array('administer telvue'), + 'description' => 'Configure system options for Telvue Push.', + 'type' => MENU_NORMAL_ITEM, + ); + $items['admin/config/system/telvue-push/settings'] = array( + 'title' => 'Telvue Push Configuration', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $items['admin/config/system/telvue-push/mapping'] = array( + 'title' => 'Telvue Push Mapping', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('telvue_push_mapping_form'), + 'access callback' => 'user_access', + 'access arguments' => array('administer telvue'), + 'description' => 'Configure field mapping for Telvue Push.', + 'type' => MENU_LOCAL_TASK, + ); + + $items['node/%node/telvue-push'] = array( + 'title' => 'Push to Telvue', + 'description' => 'Pushes metadata to Telvue if it doesn\'t exist', + 'page callback' => 'telvue_push_push', + 'page arguments' => array(1), + 'access callback' => 'user_access', + 'access arguments' => array('push to telvue'), + 'type' => MENU_CALLBACK, + ); + + return $items; + +} + +/** + * Builds the admininstration settings form. + */ +function telvue_push_admin_settings($form, &$form_state) { + $form = array(); + + $form['telvue_push_on_save'] = array( + '#type' => 'checkbox', + '#title' => t('Push Metadata to Telvue when Show is Created or Updates'), + '#default_value' => variable_get('telvue_push_on_save', 0), + '#description' => t(''), + ); + + $form['telvue_delete_days'] = array( + '#type' => 'textfield', + '#title' => t('Days Before the Program is Deleted'), + '#size' => 25, + '#maxlength' => 25, + '#default_value' => variable_get('telvue_delete_days', NULL), + '#description' => t('Number of Days to Add current date before the Program is deleted from Telvue. Set to 0 to never delete. IMPORTANT: Programs that are scheduled to air will NOT be deleted. Deleting the Program metadata does NOT delete the MPEG2 from VOL1.'), + ); + + $form = system_settings_form($form); + return ($form); +} + +function telvue_push_get_mapping_targets() { + $targets = array( + 'program' => array('label' => t('Program')), + 'episode' => array('label' => t('Episode')), + 'episode_code' => array('label' => t('Episode code')), + 'description' => array('label' => t('Description')), + 'contributor' => array( + 'label' => t('Contributor'), + 'description' => t('64 characters or less'), + ), + 'location' => array( + 'label' => t('Location'), + 'description' => t('32 characters or less'), + ), + ); + + return $targets; +} + +/** + * Edit field mapping. + */ +function telvue_push_mapping_form($form, &$form_state) { + + $form['help'] = array( + '#markup' => t('Select a Source entity and Source bundle, then map the entity fields to the Telvue Metadata Fields.'), + ); + + $defaults = variable_get('telvue_push_mapping', ''); + + // Select the target entity type. + $entity_options = array(); + foreach (entity_get_info() as $entity_type => $entity_info) { + $entity_options[$entity_type] = $entity_info['label']; + } + $entity_options = array('' => t('- Select an entity -')) + $entity_options; + + if (isset($form_state['values']['source_entity'])) { + $selected_entity = $form_state['values']['source_entity']; + } + elseif (isset($defaults['source_entity']) && !empty($defaults['source_entity'])) { + $selected_entity = $defaults['source_entity']; + } + else { + $selected_entity = key($entity_options); + } + + $form['source_entity'] = array( + '#title' => t('Source entity'), + '#type' => 'select', + '#options' => $entity_options, + '#default_value' => $selected_entity, + '#ajax' => array( + 'callback' => 'telvue_push_mapping_form_entity_ajax_callback', + 'wrapper' => 'telvue-push-bundle-wrapper', + ), + ); + + $form['bundle_container'] = array( + '#type' => 'container', + '#prefix' => '
', + '#suffix' => '
', + ); + + $form['target_container'] = array( + '#type' => 'container', + '#prefix' => '
', + '#suffix' => '
', + ); + + if (!empty($defaults['source_entity']) || !empty($form_state['values']['source_entity'])) { + $bundle_options = array(); + foreach (field_info_bundles($selected_entity) as $bundle => $bundle_info) { + $bundle_options[$bundle] = $bundle_info['label']; + } + $bundle_options = array('' => t('- Select a bundle -')) + $bundle_options; + + if (isset($form_state['values']['source_bundle'])) { + $selected_bundle = $form_state['values']['source_bundle']; + } + elseif (isset($defaults['source_bundle']) && !empty($defaults['source_bundle'])) { + $selected_bundle = $defaults['source_bundle']; + } + else { + $selected_bundle = key($bundle_options); + } + + $form['bundle_container']['source_bundle'] = array( + '#title' => t('Source bundle'), + '#type' => 'select', + '#options' => $bundle_options, + '#default_value' => $selected_bundle, + '#ajax' => array( + 'callback' => 'telvue_push_mapping_form_bundle_ajax_callback', + 'wrapper' => 'telvue-push-target-wrapper', + ), + ); + + if (!empty($defaults['source_bundle']) || !empty($form_state['values']['source_bundle'])) { + $target_options = telvue_push_get_mapping_targets(); + // $entity_fields = field_info_instances($selected_entity, $selected_bundle); + // $extra_fields = field_info_extra_fields($selected_entity, $selected_bundle, 'form'); + $entity_properties = entity_get_property_info($selected_entity); + + $field_options = array(); + // foreach ($entity_fields as $field => $field_info) { + // $field_options[$field] = $field_info['label'] . ' (' . $field_info['field_name'] . ')'; + // } + // foreach ($extra_fields as $field => $extra_field) { + // $field_options[$field] = $extra_field['label'] . ' (' . $field . ')'; + // } + foreach ($entity_properties['bundles'][$selected_bundle]['properties'] as $field => $field_info) { + $field_options[$field] = $field_info['label'] . ' (' . $field . ')'; + } + foreach ($entity_properties['properties'] as $prop => $prop_info) { + $field_options[$prop] = $prop_info['label'] . ' (' . $prop . ')'; + } + + $field_options = array('' => t('- Not mapped -')) + $field_options; + + $form['target_container']['target'] = array( + '#type' => 'fieldset', + '#title' => $bundle_options[$selected_bundle] . ' ' . t('fields'), + '#collapsible' => FALSE, + '#collapsed' => FALSE, + ); + + foreach ($target_options as $key => $target) { + $form['target_container']['target'][$key] = array( + '#type' => 'select', + '#title' => $target['label'], + '#description' => isset($target['description']) ? $target['description'] : '', + '#options' => $field_options, + '#default_value' => (isset($defaults[$key]) && !empty($defaults[$key])) ? $defaults[$key] : key($field_options), + ); + } + } + + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +function telvue_push_mapping_form_submit($form, $form_state) { + $targets = array( + 'source_entity' => array('label' => t('Source entity')), + 'source_bundle' => array('label' => t('Source bundle')), + ); + $targets += telvue_push_get_mapping_targets(); + + foreach ($targets as $key => $value) { + $variables[$key] = ''; + if (!empty($form_state['values'][$key])) { + $variables[$key] = $form_state['values'][$key]; + } + } + + variable_set('telvue_push_mapping', $variables); + drupal_set_message(t('Telvue Push field mapping has been saved.')); +} + +/** + * Ajax callback for the handler settings form. + * + * @see telvue_push_mapping_form() + */ +function telvue_push_mapping_form_entity_ajax_callback($form, $form_state) { + return $form['bundle_container']; +} + +function telvue_push_mapping_form_bundle_ajax_callback($form, $form_state) { + return $form['target_container']; +} + +/** + * Implementation of hook_node_insert(). + */ +function telvue_push_node_insert($node) { + + if ($node->type == 'cm_show' && variable_get('telvue_push_on_save', 0)) { + drupal_goto('node/' . $node->nid . '/telvue-push'); + } + + //drupal_goto('node/' . $node->nid); +} + +/** + * Implementation of hook_node_update(). + */ +function telvue_push_node_update($node) { + + if ($node->type == 'cm_show' && variable_get('telvue_push_on_save', 0)) { + drupal_goto('node/' . $node->nid . '/telvue-push'); + } + + //drupal_goto('node/' . $node->nid); +} + +function telvue_push_push($node, $return = TRUE) { + + //check to make sure the Telvue API module has been configured + $server = variable_get('telvue_uri', NULL); + $username = variable_get('telvue_user', NULL); + $mapping = variable_get('telvue_push_mapping', ''); + $src_entity = $mapping['source_entity']; + $src_bundle = $mapping['source_bundle']; + + $lang = $node->language; + + if (!$server || !$username) { + drupal_set_message(t('Telvue API is NOT Configured')); + drupal_goto('node/' . $node->nid); + } + + // extract mapped values + $mapped = array(); + foreach ($mapping as $key => $field) { + if (!empty($mapping[$key]) && !in_array($key, array('source_entity', 'source_bundle'))) { + $value = _telvue_push_field_extract_value($src_entity, $node, $field, $lang); + $mapped[$key] = $value; + } + } + + // CLEANUP FILENAME + if (isset($node->field_expected_filename[$lang][0]['value'])) { + + if (function_exists('transliteration_clean_filename')) { + $transliterated = transliteration_clean_filename($filename, $node->language); + } + + $filename = $node->field_expected_filename[$lang][0]['value']; + + //strip common video suffixes + $filename = str_replace(".mpg", "", $filename); + $filename = str_replace(".mov", "", $filename); + $filename = str_replace(".mp4", "", $filename); + $filename = str_replace(".wmv", "", $filename); + $filename = str_replace(".ogg", "", $filename); + $filename = str_replace(".ogv", "", $filename); + $filename = str_replace(".mpeg", "", $filename); + $filename = str_replace(".avi", "", $filename); + + $filename = $filename . '.mpg'; + + } + + if (!$filename) { + drupal_set_message(t('Expected Filename is Required to Push to Telvue')); + drupal_goto('node/' . $node->nid); + } + + $duration = isset($node->field_expected_duration[$lang][0]['value']) ? $node->field_expected_duration[$lang][0]['value'] : 1; + + //dsm($node); + //IF CLOUDCAST + if (!empty($mapping['description']) && $mapped['description']) { + $description = $mapped['description']; + } + elseif (isset($node->field_cloudcast[$lang][0]['value']) && $node->field_cloudcast[$lang][0]['value']) { + $description = isset($node->body[$lang][0]['value']) ? $node->body[$lang][0]['value'] . ' [cc]' : '[cc]'; + } + else { + $description = isset($node->body[$lang][0]['value']) ? $node->body[$lang][0]['value'] : NULL; + } + + if (!isset($program['delete_datetime'])) { + $delete_days = variable_get('telvue_delete_days', NULL); + if ($delete_days) { + $delete_datetime = date('Y-m-d g:i P', time() + ($delete_days * 24 * 60 * 60)); + } + else { + $delete_datetime = new SoapVar('', XSD_ANYXML); + } + } + + //IF EPISODE + if (!empty($mapping['episode']) && $mapped['episode']) { + $episode = $mapped['episode']; + } + elseif (isset($node->field_episode[$lang][0]['value']) && $node->field_episode[$lang][0]['value']) { + $episode = $node->field_episode[$lang][0]['value']; + } + else { + $episode = new SoapVar('', XSD_ANYXML); + } + + //IF EPISODE CODE + if (!empty($mapping['episode_code']) && $mapped['episode_code']) { + $episode_code = $mapped['episode_code']; + } + elseif (isset($node->field_episode_code[$lang][0]['value']) && $node->field_episode_code[$lang][0]['value']) { + $episode_code = $node->field_episode_code[$lang][0]['value']; + } + else { + $episode_code = new SoapVar('', XSD_ANYXML); + } + + //IF CONTRIBUTOR + if (!empty($mapping['contributor']) && $mapped['contributor']) { + $contributor = $mapped['contributor']; + } + elseif (isset($node->field_contributor[$lang][0]['value']) && $node->field_contributor[$lang][0]['value']) { + $contributor = $node->field_contributor[$lang][0]['value']; + } + else { + $contributor = new SoapVar('', XSD_ANYXML); + } + + //IF LOCATION + if (!empty($mapping['location']) && $mapped['location']) { + $location = $mapped['location']; + } + elseif (isset($node->field_location[$lang][0]['value']) && $node->field_location[$lang][0]['value']) { + $location = $node->field_location[$lang][0]['value']; + } + else { + $location = new SoapVar('', XSD_ANYXML); + } + + // map other fields + if (!empty($mapping['program']) && $mapped['program']) { + $program_val = $mapped['program']; + } + else { + $program_val = $node->title; + } + + //prepare show fields as the program array to send to Telvue + $program = array( + 'program' => $program_val, + 'episode' => $episode, + 'episode_code' => $episode_code, + 'description' => $description, + 'delete_datetime' => $delete_datetime, + 'expected_filename' => $filename, + 'expected_duration' => $duration, + 'contributor' => $contributor , + 'location' => $location, + 'username' => $username, + ); + + ; + + // check to see if the file already exists + if (telvue_content_metadata_by_filename($filename)) { + drupal_set_message(t('Expected Filename is Already Exists')); + drupal_goto('node/' . $node->nid); + } + else { + $response = telvue_addprogram($program, $server); + + drupal_set_message($node->title . ' Pushed to Telvue'); + + if ($return) { + drupal_goto('node/' . $node->nid); + } + } +} + +function telvue_content_metadata_by_filename($filename) { + + $server = variable_get('telvue_uri', NULL); + $url = $server . '/content_metadata_by_filename/' . $filename; + $url_headers = @get_headers($url); + if($url_headers[0] == 'HTTP/1.1 200 OK') { + $response = simplexml_load_file($url); + } else { + // Error + return FALSE; + } + + $json = json_encode($response); + $array = json_decode($json,TRUE); + + return $array; + +} + +/** + * Implements hook_node_operations(). + * Provides a 'Push to Telvue' option. + */ +function telvue_push_node_operations() { + + $operations['push-to-telvue'] = array( + 'label' => t('Push to Telvue'), + 'callback' => 'telvue_push_node_operations_callback', + ); + return $operations; +} + +/** + * Node operation callback: + * Updates the selected nodes' language. + * Stores the new language to be assigned; then languageassign_node_presave() + * updates the node and body languages. + */ +function telvue_push_node_operations_callback($nodes) { + foreach ($nodes as $nid) { + $node = node_load($nid); + if ($node->type == 'cm_show') { + telvue_push_push($node, FALSE); + } + } +} + +/** +* Implementation of hook_form_alter +*/ +function telvue_push_form_alter(&$form, $form_state, $form_id) { + // [PATCHED] by wluisi 8/8 + if ($form_id == 'cm_show_node_form' && user_access('push to telvue')) { + //dsm($form); + $form['actions']['telvue_save_and_push_button'] = array( + '#type' => 'submit', + '#value' => 'Save and Push', + '#submit' => array('telvue_push_add_redirect'), + '#weight' => 99 + ); + } +} + +function telvue_push_add_redirect($form, &$form_state){ + + unset($_GET['destination']); + $node = node_form_submit_build_node($form, $form_state); + $insert = empty($node->nid); + node_save($node); + $node_link = l(t('view'), 'node/' . $node->nid); + $watchdog_args = array( + '@type' => $node->type, + '%title' => $node->title, + ); + $t_args = array( + '@type' => node_type_get_name($node), + '%title' => $node->title, + ); + + if ($insert) { + watchdog('content', '@type: added %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link); + drupal_set_message(t('@type %title has been created.', $t_args)); + } + else { + watchdog('content', '@type: updated %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link); + drupal_set_message(t('@type %title has been updated.', $t_args)); + } + if ($node->nid) { + $form_state['values']['nid'] = $node->nid; + $form_state['nid'] = $node->nid; + $form_state['redirect'] = 'node/' . $node->nid . '/telvue-push'; + } + else { + // In the unlikely case something went wrong on save, the node will be + // rebuilt and node form redisplayed the same way as in preview. + drupal_set_message(t('The post could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + // Clear the page and block caches. + cache_clear_all(); + +} + +function _telvue_push_field_extract_value($entity_type, $entity, $field_name, $delta = 0, array $options = array()) { + $value = FALSE; + + // TODO: handle multiple values + $field_info = field_info_field($field_name); + $raw = field_extract_values($entity_type, $entity, $field_name); + + // related to a Field API field + if ($field_info) { + switch ($field_info['type']) { + case 'taxonomy_term_reference': + $items = array(); + foreach ($raw as $tid => $value) { + $items[] = $raw->name; + } + $value = implode(',', $items); + break; + + case 'entityreference': + $value = $raw[0]->title; + break; + + default: + $value = $raw[0]; + break; + } + } + else { + $entity_properties = entity_get_property_info($entity_type); + $field = $entity_properties['properties'][$field_name]['schema field']; + + switch ($field) { + case 'uid': + $account = user_load($entity->{$field}); + if (module_exists('civicrm_realname') && !empty($account->display_name)) { + $value = $account->display_name; + } + elseif (module_exists('realname') && !empty($account->realname)) { + $value = $account->realname; + } + else { + $value = $account->name; + } + break; + + default: + $value = $entity->{$field}; + } + } + + + return $value; +} diff --git a/modules/telvue_show_fields/telvue_show_fields.features.field.inc b/modules/telvue_show_fields/telvue_show_fields.features.field.inc new file mode 100644 index 0000000..0e13374 --- /dev/null +++ b/modules/telvue_show_fields/telvue_show_fields.features.field.inc @@ -0,0 +1,217 @@ + array( + 'active' => '1', + 'cardinality' => '1', + 'deleted' => '0', + 'entity_types' => array( + 0 => 'node', + ), + 'field_name' => 'body', + 'foreign keys' => array( + 'format' => array( + 'columns' => array( + 'format' => 'format', + ), + 'table' => 'filter_format', + ), + ), + 'indexes' => array( + 'format' => array( + 0 => 'format', + ), + ), + 'locked' => '0', + 'module' => 'text', + 'settings' => array(), + 'translatable' => '0', + 'type' => 'text_with_summary', + ), + 'field_instance' => array( + 'bundle' => 'cm_show', + 'default_value' => NULL, + 'deleted' => '0', + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'body', + 'label' => 'Description', + 'required' => 0, + 'settings' => array( + 'display_summary' => 0, + 'text_processing' => '1', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'rows' => '20', + 'summary_rows' => 5, + ), + 'type' => 'text_textarea_with_summary', + 'weight' => '1', + ), + ), + ); + + // Exported field: 'node-cm_show-field_expected_duration'. + $fields['node-cm_show-field_expected_duration'] = array( + 'field_config' => array( + 'active' => '1', + 'cardinality' => '1', + 'deleted' => '0', + 'entity_types' => array(), + 'field_name' => 'field_expected_duration', + 'foreign keys' => array(), + 'indexes' => array(), + 'locked' => '0', + 'module' => 'hms_field', + 'settings' => array(), + 'translatable' => '0', + 'type' => 'hms_field', + ), + 'field_instance' => array( + 'bundle' => 'cm_show', + 'default_value' => NULL, + 'deleted' => '0', + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'hms_field', + 'settings' => array( + 'format' => 'h:mm', + 'leading_zero' => TRUE, + ), + 'type' => 'hms_default_formatter', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_expected_duration', + 'label' => 'Expected Duration', + 'required' => 0, + 'settings' => array( + 'format' => 'h:mm:ss', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 0, + 'module' => 'hms_field', + 'settings' => array(), + 'type' => 'hms_default_widget', + 'weight' => '3', + ), + ), + ); + + // Exported field: 'node-cm_show-field_expected_filename'. + $fields['node-cm_show-field_expected_filename'] = array( + 'field_config' => array( + 'active' => '1', + 'cardinality' => '1', + 'deleted' => '0', + 'entity_types' => array(), + 'field_name' => 'field_expected_filename', + 'foreign keys' => array( + 'format' => array( + 'columns' => array( + 'format' => 'format', + ), + 'table' => 'filter_format', + ), + ), + 'indexes' => array( + 'format' => array( + 0 => 'format', + ), + ), + 'locked' => '0', + 'module' => 'text', + 'settings' => array( + 'max_length' => '255', + ), + 'translatable' => '0', + 'type' => 'text', + ), + 'field_instance' => array( + 'bundle' => 'cm_show', + 'default_value' => NULL, + 'deleted' => '0', + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_expected_filename', + 'label' => 'Expected Filename', + 'required' => 0, + 'settings' => array( + 'text_processing' => '0', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => '60', + ), + 'type' => 'text_textfield', + 'weight' => '2', + ), + ), + ); + + // Translatables + // Included for use with string extractors like potx. + t('Description'); + t('Expected Duration'); + t('Expected Filename'); + + return $fields; +} diff --git a/modules/telvue_show_fields/telvue_show_fields.info b/modules/telvue_show_fields/telvue_show_fields.info new file mode 100644 index 0000000..fdba88a --- /dev/null +++ b/modules/telvue_show_fields/telvue_show_fields.info @@ -0,0 +1,19 @@ +name = Telvue Show Fields +description = Adds fields required for Telvue Integration +core = 7.x +package = Community Media +dependencies[] = features +dependencies[] = hms_field +dependencies[] = list +dependencies[] = options +features[features_api][] = api:1 +features[field][] = node-cm_show-body +features[field][] = node-cm_show-field_expected_duration +features[field][] = node-cm_show-field_expected_filename + +; Information added by Drupal.org packaging script on 2014-04-29 +version = "7.x-1.0-alpha5" +core = "7.x" +project = "telvue" +datestamp = "1398793128" + diff --git a/modules/telvue_show_fields/telvue_show_fields.module b/modules/telvue_show_fields/telvue_show_fields.module new file mode 100644 index 0000000..44788b0 --- /dev/null +++ b/modules/telvue_show_fields/telvue_show_fields.module @@ -0,0 +1,5 @@ +name); + } +} \ No newline at end of file diff --git a/telvue.module b/telvue.module new file mode 100644 index 0000000..ae595a1 --- /dev/null +++ b/telvue.module @@ -0,0 +1,246 @@ + array( + 'title' => t('Administer Telvue'), + 'description' => t('Allows users to configure Telvue settings.'), + 'restrict access' => TRUE, + ), + ); + + return $permissions; +} + + +/** + * Implements hook_menu(). + */ +function telvue_menu() { + + // Standard Administration settings. + $items['admin/config/system/telvue'] = array( + 'title' => 'Telvue Configuration', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('telvue_admin_settings'), + 'access callback' => 'user_access', + 'access arguments' => array('administer telvue'), + 'description' => 'Configure system settings for Telvue integration.', + ); + + return $items; +} + +/** + * Builds the admininstration settings form. + */ +function telvue_admin_settings($form, &$form_state) { + $form = array(); + + if (variable_get('telvue_uri', NULL)) { + $version = telvue_software_version(variable_get('telvue_uri', NULL), variable_get('telvue_api_key', NULL)); + + if (isset($version['software_version'])) { + drupal_set_message(t('Successfully communicating with the Telvue. Telvue is running version ') . $version['software_version']); + } else { + if ($version['status'] == 'Access Denied') { + drupal_set_message(t('Connected to Telvue, but API key is either not included or not correct. API Key is required for advanced features like Telvue Push.'), 'warning'); + } else { + drupal_set_message(t('There is a problem communicating with the server. Please check the URI.'), 'error'); + } + } + } + + $form['telvue_uri'] = array( + '#type' => 'textfield', + '#title' => t('URI'), + '#size' => 50, + '#maxlength' => 50, + '#default_value' => variable_get('telvue_uri', NULL), + '#description' => t('IP address or URL of the Telvue server including the :3000 (ie. http://b1000.yourdomain.org:3000 or https://172.25.0.xx:3000)'), + ); + + $form['telvue_connection_error'] = array( + '#type' => 'textarea', + '#title' => t('Connection Error Message'), + '#rows' => 10, + '#cols' => 5, + '#default_value' => variable_get('telvue_connection_error', t('Unable to update')), + '#description' => t('Enter the message users will see in the blocks if Drupal cannot connect to the Telvue API. If left blank, the block will not be displayed.'), + ); + + $form['telvue_cache'] = array( + '#type' => 'checkbox', + '#title' => t('Cache results from API when possible'), + '#default_value' => variable_get('telvue_cache', 0), + '#description' => t(''), + ); + + $form['telvue_user'] = array( + '#type' => 'textfield', + '#title' => t('Username'), + '#size' => 25, + '#maxlength' => 25, + '#default_value' => variable_get('telvue_user', NULL), + '#description' => t('This is a user on the Telvue server with the API option enabled.'), + ); + + $form['telvue_api_key'] = array( + '#type' => 'textfield', + '#title' => t('API Key'), + '#size' => 25, + '#maxlength' => 25, + '#default_value' => variable_get('telvue_api_key', NULL), + '#description' => t(''), + ); + + $form['telvue_verbose_logging'] = array( + '#type' => 'checkbox', + '#title' => t('Verbose Logging Mode'), + '#default_value' => variable_get('telvue_verbose_logging', 0), + '#description' => t('This option will add log messages at several points in during the API connections making it easier to diagnose configuration issues.'), + ); + + $form = system_settings_form($form); + return ($form); +} + +function telvue_hms2sec($hms) { + list($h, $m, $s) = explode (":", $hms); + $seconds = 0; + $seconds += (intval($h) * 3600); + $seconds += (intval($m) * 60); + $seconds += (intval($s)); + return $seconds; +} + + +/** + * Implementation of Telvue APIs + * http://www.telvue.com/support/product-documentation/princeton-server-api-docs/content-methods/ + * + */ + +/** + * Pushes program to Telvue server based on field mapping in custom module + * + */ +function telvue_addprogram($program, $server) { +/* + + + $rating = $airing_items[$s]['adult'] ? ' (TV-MA) ' : NULL; + $program_code = $airing_items[$s]['nid']; + + $program = $airing_items[$s]['title'] . $rating; + $delete_datetime = date('Y-m-d g:i P', time() + (30 * 24 * 60 * 60)); + $ingest_datetime = date('Y-m-d g:i P', time()); + $expected_duration = $airing_items[$s]['duration']; + $expected_filename = $airing_items[$s]['filename']; + +*/ + + if (!isset($program['delete_datetime'])) { + // if it isn't set, use 30 days + $program['delete_datetime'] = date('Y-m-d g:i P', time() + (30 * 24 * 60 * 60)); + } + + if (!isset($program['ingest_datetime'])) { + $program['import_datetime'] = date('Y-m-d g:i P', time()); + } + + + if (!$program['expected_filename'] || !$program['expected_duration']) { + return 'Failed'; + } + + + try { + $service = new SoapClient($server . '/program_service/wsdl'); + $result = $service->AddProgram( + new SoapVar('', XSD_ANYXML), + $program['program'], + $program['episode'], + $program['episode_code'], + $program['description'], + $program['delete_datetime'], + $program['import_datetime'], + $program['expected_duration'], + $program['expected_filename'], + $program['contributor'], + $program['location'], + $program['username'] + ); + + //http://www.telvue.com/support/product-documentation/princeton-server-api-docs/content-methods/using-soap-and-ruby-to-add-a-tbd-content-record/ + + //'M8', // program_code + //'Example TBD Program', //program + //'S8', // episode + //'8', // episode_code + //'This is an example TBD added via soap.', // description + //new SoapVar('', XSD_ANYXML), // delete_datetime + //'2008-10-21 14:39:23-04:00', //import_datetime + //80, //expected_duration + //'exampled_tbd.mpg', //expected_filename + //'Poor Steve', //contributor + //'Princeton, NJ', // location + //'psgadmin' // username + + + if ($result[0] == 'SUCCEEDED') { + $return = t('File successfully transfered'); + watchdog('Telvue', 'telvue_addprogram: Succeeded'); + } + else { + $return = t('Transfer failed. ') . $result[1]; + watchdog('Telvue', 'telvue_addprogram: Failed ' . $result[1]); + } + } // end try + + catch (SoapFault $fault) { + trigger_error("The following SOAP Error was generated, SOAP Fault: (faultcode: {$fault->faultcode}, faultstring: {$fault->faultstring})", E_USER_ERROR); + }// catch + + + return $return; +} + +/** + * Edit Program on Telvue server based on ProgramID for the server + * + */ +function telvue_editprogram($program, $server) { + +} + +/** + * Deletes Program on Telvue server based on ProgramID for the server + * + */ +function telvue_deleteprogram($programid, $server) { + $username = 'soap'; //@TODO: set to vailable defined in module + $client = new SoapClient($server['ip'] . '/program_service/wsdl'); + $soap_result = $client->__soapCall("DeleteProgram", array($program_id, $username)); + return $soap_result; +} + +/** + * Gets Software Version from Telvue server + * + */ +function telvue_software_version($server, $apikey) { + $url = $server . '/xml/software_version?api_key=' . $apikey; + $response = simplexml_load_file($url); + + $json = json_encode($response); + $array = json_decode($json,TRUE); + + return $array; +} + + diff --git a/templates/telvue-playing-now.tpl.php b/templates/telvue-playing-now.tpl.php new file mode 100644 index 0000000..1243c97 --- /dev/null +++ b/templates/telvue-playing-now.tpl.php @@ -0,0 +1,3 @@ +

'; + -
+
\ No newline at end of file diff --git a/templates/telvue-show-next-airing.tpl.php b/templates/telvue-show-next-airing.tpl.php new file mode 100644 index 0000000..1243c97 --- /dev/null +++ b/templates/telvue-show-next-airing.tpl.php @@ -0,0 +1,3 @@ +

'; + -
+
\ No newline at end of file diff --git a/templates/telvue-show-now-and-next-airing.tpl.php b/templates/telvue-show-now-and-next-airing.tpl.php new file mode 100644 index 0000000..33836f1 --- /dev/null +++ b/templates/telvue-show-now-and-next-airing.tpl.php @@ -0,0 +1,5 @@ +

+ -
+
+Playing Next: +
\ No newline at end of file