Cacao7w7

sss

Jun 27th, 2018
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.34 KB | None | 0 0
  1. ###############################################################################
  2. # Name: Youtube Title V2
  3. # Author: Jan Milants <[email protected]>
  4. # Version: 2.1 (22/08/2016)
  5. # Eggdrop Version: 1.6.x
  6. # Requires TCL version: 8.5
  7. # Package dependencies: http, tls, json
  8. # Credits: Based on original YouTube Script
  9. # Design inspiration from
  10. # youtube.tcl by Mookie.
  11. ###############################################################################
  12. # Description
  13. # -------------
  14. # La escritura supervisa canales de texto para relaciones a Youtube.
  15. # Cuando encontrado, esto preguntará al servidor google para detalles, como el título de vídeo
  16. # y el número de visiones del vídeo youtube y anuncian los resultados en el canal.
  17. # La escritura también apoya la busca youtube con la orden, !youtube <texto a buscar>
  18. # o "!youtube <texto a buscar>". Opcionalmente, el número de resultados de la búsqueda deseados puede ser
  19. # especificando la utilización"!youtube + <el número de resultados> <buscan el texto>".
  20. # En la respuesta, la pregunta de búsqueda será pasada al youtube API y el mejor
  21. # el resultado (s) que está será unido en el canal.
  22. #
  23. # Esta escritura será activa en cualquier canal en el cual ella resida con el "youtube" flag.
  24. # existe dos formas en activar esta tcl una mediante el partylien ejemplo ".chanset #tu-canal +youtube" y la otra
  25. # forma es activando en el canal abierto ejemplo !youtube on
  26. # en ambos comanodos solo puede ser activada por el usuario que tenga los flags mno.
  27. #
  28. # Esta escritura pone en práctica una protección de antiflood, muy básica para búsquedas de YouTube,
  29. # requiriendo a usuarios, o mejor dicho todos los clientes con mismo userhost, esperar
  30. # un intervalo predeterminado antes de que ellos puedan buscar otra vez.
  31. # Nota que esto no aplica a YouTube URLs pegado en el canal.
  32. #
  33. # Getting your own Google API key
  34. # ---------------------------------
  35. # This script uses the Google Youtube Data API V3, which requires an API key to
  36. # authorize access to the API and is used as basis for limiting request per day etc.
  37. # Instructions can be found on
  38. # https://developers.google.com/youtube/registering_an_application
  39. # Required steps in short:
  40. # 1. Go to the Google developers console https://console.developers.google.com
  41. # 2. Create a new project. Give it a name like 'eggdrop', doesn't matter much.
  42. # 3. When the project is loaded, select menu "Library" under "API Manager"
  43. # This should load the list of available Google APIs on the right.
  44. # 4. In the list of APIs, select the "YouTube Data API".
  45. # This should load a page describing the "YouTube Data API v3".
  46. # 5. Enable the API for you application by clicking "Enable" next to the API name.
  47. # 6. Select menu "Credentials" and click "Create credentials".
  48. # 7. Select type "API key" type "server key".
  49. # 8. Optionally, fill in the IP(s) or IP range from which the eggdrop bot will send
  50. # requests to google's servers. This is a whitelist, if the request
  51. # comes from a different IP, it will be rejected.
  52. # Note: If my-ip or my-hostname is configured in eggdrop.conf, they should
  53. # be entered here.
  54. # 9. Click "Create".
  55. # You now have an API KEY; copy it to the config section below.
  56. #
  57. # !!! IMPORTANT !!!
  58. # When loading this script alongside other scripts which initiate web service calls,
  59. # ensure this script is loaded last! The script creates a handler for HTTPS connection
  60. # and sets the source IP to the my-ip or my-hostname from eggdrop.conf.
  61. # Most other scripts will not correctly enforce the source IP of requests and
  62. # can overwrite this scripts HTTPS handler. This results in connections coming from another
  63. # IP on the machine and may thus be rejected by the Google API Servers.
  64. # The typical error message logged would be "Error processing web service reply".
  65. #
  66. ###############################################################################
  67. # Changes:
  68. # 2.10 22/08/16
  69. # Added a default API key since IPs don't need to be individually whitelisted anymore.
  70. # Added support for YouTube searches returning multiple search results.
  71. # Added basic anti-flood measures by implementing a minimum interval between searches.
  72. # Updated dependency checking to be non-fatal to the hosting bot. (Suggested by caesar.)
  73. # Updated documentation for creating your own API key to match new dev console.
  74. # Fixed the socket not enabling TLS usage on some systems. (Fix suggested by Madalin.)
  75. # 2.00 28/08/14
  76. # Started development (Jan).
  77. # Almost complete rewrite most notable changes:
  78. # * Use the YouTube Data API V3. (Requires TLS support!)
  79. # * Strip out flat_json_decoder and use json & dict packages instead.
  80. # * Strip out tinyurl support. Better to use youtu.be in the response.
  81. # * Many more data elements supported in response format (possible by new API).
  82. # * Added possiblity to turn the script on/off on a channel by channel basis.
  83. # * Added ability to search youtube and return the first result.
  84. # 0.51 09/30/13
  85. # Small correction for caps in url (but not video id)
  86. # 0.5 01/02/09
  87. # Added better error reporting for restricted youtube content.
  88. # 0.4 10/11/09
  89. # Changed title scraping method to use the oembed api.
  90. # Added crude JSON decoder library.
  91. # 0.3 02/03/09
  92. # Fixed entity decoding problems in return titles.
  93. # Added customisable response format.
  94. # Fixed rare query string bug.
  95. ###############################################################################
  96. #
  97. # Configuration
  98. #
  99. ###############################################################################
  100.  
  101. # API key assigned to your Google account.
  102. # Find detailed instructions for getting your own API key above or use mine.
  103. set youtube(api_key) "AIzaSyBVmqrzuW_CW0wc6qwzS6KEqrynY4mr2mw"
  104.  
  105. # Base URI for links to YouTube videos.
  106. # Either use the normal YouTube link or youtu.be for shorter URLs.
  107. # I'd recommend keeping the HTTPS to avoid exposing user data.
  108. set youtube(base_url) "https://www.youtube.com/watch?v="
  109. #set youtube(base_url) "https://www.youtu.be/"
  110.  
  111. # Date/time format
  112. # The format to be used when showing dates, for example in publish date.
  113. # All times are in UTC.
  114. #
  115. # Available tokens:
  116. # %­year% 4 digit year notation
  117. # %­month% 2 digit month notation
  118. # %day% 2 digit day of the month notation
  119. # %­hours% 2 digit hour notation on a 24hours basis
  120. # %­minutes% 2 digit minutes notation
  121. # %­seconds% 2 digit seconds notation
  122. #
  123. # Example:
  124. # "%day%/%­month%/%­year% %­hours%:%­minutes% UTC"
  125. set youtube(date_format) "%day%/%­month%/%­year% %­hours%:%­minutes% UTC"
  126.  
  127.  
  128. # Response Formats
  129. # Template of the reply to be send to the channel showing the YouTube video details.
  130. # A separate response can be set for replies to a pasted URL or to a query.
  131. #
  132. # Available tokens in the response format:
  133. # %botnick% Nickname of bot
  134. # %­poster% Nickname of person who posted the YouTube link
  135. # %­youtube_url% URL to the YouTube link (This may not be the exact same
  136. # URL that was posted since it's rewritten based on the format
  137. # above to ensure all links posted by the bot are HTTPS.)
  138. # %­id% ID of the linked YouTube video.
  139. # %author% Author/Uploader/channel of the video.
  140. # %­title% Title of YouTube link
  141. # %description% Description of the video.
  142. # (Note that this is generally a VERY long text!)
  143. # %­published% Date & time the video was published.
  144. # %­views% The number of times the video has been viewed.
  145. # %­likes% The number of users who have "liked" the video.
  146. # %dislikes% The number of users who have "disliked" the video.
  147. # %­length% Length of the video.
  148. # Tokens only available in the response to searches (q_resp_format):
  149. # %­query% The original search string.
  150. # %­res_nbr% The index of the search result being shown.
  151. # %­res_tot% Total number of search results.
  152. #
  153. # Example:
  154. # "\002YouTube\002: %­poster%: %­youtube_url% - \"\002%­title%\002\" (Uploaded by \"%author%\" on %­published%) - Length: %­length% - Views: %­views% - Likes / Dislikes: %­likes% / %dislikes%"
  155. # The template used when looking up a URL found in the channel
  156. set youtube(response_format) "\002\00301,00You\00300,04Tube\003\002: %­poster%: %­youtube_url% - \"\002%­title%\002\" (Cargado por \"%author%\" en fecha de %­published%) - duracion: %­length% - total veces visto: %­views% - le gustan / no les gustan: %­likes% / %dislikes%"
  157. # The template used when replying to a search query.
  158. set youtube(q_resp_format) "\002\00301,00You\00300,04Tube\003\002: %­poster%: Resultado(s) %­res_nbr%/%­res_tot% para la busqueda '%­query%': %­youtube_url% - \"\002%­title%\002\" (Cargado por \"%author%\" en fecha de %­published%) - duracion: %­length% - total veces visto: %­views% - le gustan / no les gustan: %­likes% / %dislikes%"
  159.  
  160. # The maximum number of characters from a YouTube title to print.
  161. set youtube(max_title_length) 64
  162.  
  163. # The maximum number of characters from a YouTube description to print.
  164. set youtube(max_desc_length) 128
  165.  
  166. # numeros de resultados para busqueda en youtube web
  167. set youtube(search_res_def) 4
  168.  
  169. # The maximum number of search results that can be requested with a YouTube search.
  170. set youtube(search_res_max) 3
  171.  
  172. # The minimum interval (in seconds) a user must wait before he can execute another search query.
  173. # Set to 0 to disable interval checking.
  174. set youtube(search_int_min) 15
  175.  
  176. ###############################################################################
  177. #
  178. # Advanced Configuration
  179. # !!! DO NOT CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING !!!
  180. #
  181. ###############################################################################
  182.  
  183. # URLs of the YouTube V3 API
  184. set youtube(api_get) "https://www.googleapis.com/youtube/v3/videos"
  185. set youtube(api_search) "https://www.googleapis.com/youtube/v3/search"
  186.  
  187. # The groups of properties to be fetched
  188. set youtube(api_part) "snippet,statistics,contentDetails"
  189.  
  190. # The fields from the selected property groups that are to be returned
  191. set youtube(api_fields) "items(id,snippet(publishedAt,title,description,channelTitle),statistics,contentDetails(duration))"
  192.  
  193. # Maximum time in milliseconds to wait for YouTube to respond
  194. set youtube(api_timeout) "30000"
  195.  
  196. # Pattern used to patch YouTube links in channel public text
  197. set youtube(pattern) {https{0,1}://.*youtu(?:\.be/|be\..*/watch\?(?:.*)v=)([A-Za-z0-9_\-]+)}
  198.  
  199. ###############################################################################
  200.  
  201. variable packages
  202.  
  203. # Check for all dependencies without killing the bot that's trying to load the script.
  204. if { [catch {package require Tcl 8.5} error] } { set "packages(Tcl 8.5)" $error }
  205. if { [catch {package require http 2.7} error] } { set "packages(http 2.7)" $error }
  206. if { [catch {package require tls} error] } { set packages(tls) $error }
  207. if { [catch {package require json} error] } { set packages(json) $error }
  208.  
  209. # If any dependencies failed loading, print the error and abort.
  210. if { [array size packages] > 0 } {
  211. foreach index [array names packages] {
  212. putlog "% YoutubeTitleV2: Error que carga paquete '$index' : $packages($index)"
  213. }
  214.  
  215. putlog "% YoutubeTitleV2: Carga abortó (Ausencia de dependencias)!"
  216. return
  217. }
  218.  
  219. ###############################################################################
  220.  
  221. # We need HTTPS support for the Google APIs..
  222. # If local IP or host is configured in the main config, use it as the source
  223. # of the outgoing connections.
  224. if { [info exists {my-ip}] == 1 && [string length ${my-ip}] > 0} {
  225. http::register https 443 [list tls::socket -myaddr ${my-ip} -tls1 1]
  226. } elseif { [info exists {my-hostname}] == 1 && [string length ${my-hostname}] > 0} {
  227. http::register https 443 [list tls::socket -myaddr ${my-hostname} -tls1 1]
  228. } else {
  229. http::register https 443 [list tls::socket -tls1 1]
  230. }
  231.  
  232. set YoutubeTitleVersion "2.1"
  233.  
  234. # Keep a dictionary of the user hosts from where search queries are currently
  235. # ignored by the script.
  236. set yt_search_ignore [dict create]
  237.  
  238. setudef flag youtube
  239. bind pubm - * public_youtube
  240. bind pub - !youtube youtube_query
  241. bind pub - !yt youtube_query
  242. bind pub - .youtube youtube_query
  243. bind pub - .yt youtube_query
  244.  
  245. ###############################################################################
  246.  
  247. proc note {msg} {
  248. putlog "% $msg"
  249. }
  250.  
  251. # Ensure strings are no longer then given length. This will cut-off the string
  252. # at the desired length and append '...'.
  253. proc shorten {text maxlen} {
  254. if { [string length $text] > [expr $maxlen - 1] } {
  255. set text [string range $text 0 [expr $maxlen - 4]]"..."
  256. }
  257. return $text
  258. }
  259.  
  260. # Convert an ISO8601 date into a more readable format..
  261. proc conv_iso8601_date {orig_date} {
  262. global youtube
  263. set pattern {(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d{1}|3[012])[T\s](?:(?:([01]\d|2[0-3]):([0-5]\d))|(24):(00)):(?:([0-5]\d)(?:[\.,](\d+))?|(60)(?:[\.,](0+))?)Z}
  264. if { [regexp $pattern $orig_date match year month day hours minutes hours_2 minutes_2 seconds milliseconds seconds_2 milliseconds_2] } {
  265. # The hour and hour_2 variables are mutually exclusive, so we append the _2 variables to
  266. # the original ones to have fewer variables to work with.
  267. append hours $hours_2
  268. append minutes $minutes_2
  269. append seconds $seconds_2
  270.  
  271. # Put everything in a dictionary so we can have a configurable time format.
  272. set tokens [dict create]
  273. dict set tokens %­year% $year
  274. dict set tokens %­month% $month
  275. dict set tokens %day% $day
  276. dict set tokens %­hours% $hours
  277. dict set tokens %­minutes% $minutes
  278. dict set tokens %­seconds% $seconds
  279.  
  280. return [string map $tokens $youtube(date_format)]
  281. } else {
  282. error "Incapaz de tratar valor de fecha ($orig_date) devuelto por servicio web."
  283. }
  284. }
  285.  
  286. # Convert an ISO8601 duration into a more readable format..
  287. proc conv_iso8601_duration {duration} {
  288. set length ""
  289. set pattern {P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)}
  290. if { [regexp $pattern $duration match years months days hours minutes seconds] } {
  291. if { [string length $years] > 0 } {
  292. append length $years Y " "
  293. }
  294. if { [string length $months] > 0 } {
  295. append length $months M " "
  296. }
  297. if { [string length $days] > 0 } {
  298. append length $days D " "
  299. }
  300. if { [string length $hours] > 0 } {
  301. append length $hours h " "
  302. }
  303. if { [string length $minutes] > 0 } {
  304. append length $minutes m " "
  305. }
  306. if { [string length $seconds] > 0 } {
  307. append length $seconds s " "
  308. }
  309. } else {
  310. error "Incapaz de tratar valor de duración ($duration) devuelto por servicio web."
  311. }
  312. return [string trim $length]
  313. }
  314.  
  315. ###############################################################################
  316.  
  317. # Process the reply string of a video lookup from the YouTube API (JSON) and add the
  318. # data to a dictionary containing all tokens the user will be able to use in the template.
  319. proc read_props {json_blob} {
  320. global youtube
  321. # Create an empty dictionary for the variables supported in the response format.
  322. set properties [dict create]
  323.  
  324. # Convert the JSON response to a dictionary.
  325. set reply [json::json2dict $json_blob]
  326.  
  327. # The web service returns a list of results, even though our query will always get 1.
  328. # So we have to take the first element from the list..
  329. if { ![dict exists $reply items] } {
  330. error "Error processing web service reply."
  331. } else {
  332. set video [lindex [dict get $reply items] 0]
  333.  
  334. # Check whether the variables we support in the response are present in the
  335. # reply from the web service. We check this one by one instead of assuming
  336. # they exist in case the API changes or someone messes with the requested fields.
  337. # Properties of the view we extract from reply..
  338. if { [dict exists $video id] } {
  339. dict set properties %­id% [dict get $video id]
  340. } else {
  341. dict set properties %­id% ""
  342. }
  343. if { [dict exists $video snippet channelTitle] } {
  344. dict set properties %author% [dict get $video snippet channelTitle]
  345. } else {
  346. dict set properties %author% ""
  347. }
  348. if { [dict exists $video snippet title] } {
  349. dict set properties %­title% [shorten "[dict get $video snippet title]" $youtube(max_title_length)]
  350. } else {
  351. dict set properties %­title% ""
  352. }
  353. if { [dict exists $video snippet description] } {
  354. dict set properties %description% [shorten "[dict get $video snippet description]" $youtube(max_desc_length)]]
  355. } else {
  356. dict set properties %description% ""
  357. }
  358. if { [dict exists $video snippet publishedAt] } {
  359. dict set properties %­published% [conv_iso8601_date [dict get $video snippet publishedAt]]
  360. } else {
  361. dict set properties %­published% ""
  362. }
  363. if { [dict exists $video statistics viewCount] } {
  364. dict set properties %­views% [dict get $video statistics viewCount]
  365. } else {
  366. dict set properties %­views% ""
  367. }
  368. if { [dict exists $video statistics likeCount] } {
  369. dict set properties %­likes% [dict get $video statistics likeCount]
  370. } else {
  371. dict set properties %­likes% ""
  372. }
  373. if { [dict exists $video statistics dislikeCount] } {
  374. dict set properties %dislikes% [dict get $video statistics dislikeCount]
  375. } else {
  376. dict set properties %dislikes% ""
  377. }
  378. if { [dict exists $video contentDetails duration] } {
  379. dict set properties %­length% [conv_iso8601_duration [dict get $video contentDetails duration]]
  380. } else {
  381. dict set properties %­length% ""
  382. }
  383. }
  384.  
  385. return $properties
  386. }
  387.  
  388. # Process the reply string of a search query to the YouTube API (JSON) and extract the
  389. # video id of the results from the reply.
  390. proc read_searchres {json_blob} {
  391. global youtube
  392. # Create an empty list containing the video IDs returned for the search query.
  393. list video_ids
  394.  
  395. # Convert the JSON response to a dictionary.
  396. set reply [json::json2dict $json_blob]
  397.  
  398. # The web service returns a list of results, even though our query will always get 1.
  399. # So we have to take the first element from the list..
  400. if { ![dict exists $reply items] } {
  401. error "Error processing web service reply."
  402. } else {
  403. foreach res [dict get $reply items] {
  404. if { [dict exists $res id videoId] } {
  405. lappend video_ids [dict get $res id videoId]
  406. }
  407. }
  408. }
  409.  
  410. return $video_ids
  411. }
  412.  
  413. # Send a request to the YouTube API to fetch the video details for
  414. # the video with the given ID.
  415. proc fetch_props {youtube_id} {
  416. global youtube
  417. # Ensure an API key has been configured..
  418. if { [info exists youtube(api_key)] == 0 || [string length $youtube(api_key)] == 0 } {
  419. error "An API key must be configured to access the Google web API!"
  420. } else {
  421. set query [http::formatQuery id $youtube_id key $youtube(api_key) \
  422. part $youtube(api_part) fields $youtube(api_fields)]
  423. set response [http::geturl "$youtube(api_get)?$query" -timeout $youtube(api_timeout)]
  424. upvar #0 $response state
  425. if [expr [http::ncode $response] == 401] {
  426. error "La posición contuvo restringido empotran datos."
  427. } else {
  428. set response_body [http::data $response]
  429. http::cleanup $response
  430. return [read_props $response_body]
  431. }
  432. }
  433. }
  434.  
  435. # Find the video ID of the first match for the given search.
  436. proc search_video {criteria results} {
  437. global youtube
  438. # Ensure an API key has been configured..
  439. if { [info exists youtube(api_key)] == 0 || [string length $youtube(api_key)] == 0 } {
  440. error "An API key must be configured to access the Google web API!"
  441. } else {
  442. set query [http::formatQuery type "video" q $criteria key $youtube(api_key) \
  443. part "id" fields "items(id(videoId))" maxResults "$results"]
  444. set response [http::geturl "$youtube(api_search)?$query" -timeout $youtube(api_timeout)]
  445. upvar #0 $response state
  446. if [expr [http::ncode $response] == 401] {
  447. error "Location contained restricted embed data."
  448. } else {
  449. set response_body [http::data $response]
  450. http::cleanup $response
  451. return [read_searchres $response_body]
  452. }
  453. }
  454. }
  455.  
  456. ###############################################################################
  457.  
  458. # This is triggered to analyse ever channel message for the presence of the YouTube URL.
  459. # When one is found, the ID is extracted and passed on to get a list of the video properties.
  460. # Finally, this list is used to fill in the tokens in the user defined reply template.
  461. proc public_youtube {nick userhost handle channel args} {
  462. global youtube botnick
  463.  
  464. if { [channel get $channel youtube] && [regexp -nocase -- $youtube(pattern) $args match video_id] } {
  465. if { [catch {set tokens [fetch_props $video_id]} error] } {
  466. note "Failed to get video details: $error (querying '$video_id')"
  467. # If the reply contained an empty ID, we assume we found no video..
  468. } elseif { [string length [dict get $tokens %­id%]] == 0 } {
  469. putserv "PRIVMSG $channel :Incapaz de encontrar un vídeo youtube con ID '$video_id'."
  470. } else {
  471. dict set tokens %botnick% $botnick
  472. dict set tokens %­poster% $nick
  473. # Rebuild the URL so we use a url shortener or force SSL
  474. # in all messages coming from us
  475. dict set tokens %­youtube_url% "$youtube(base_url)$video_id"
  476.  
  477. set result [string map $tokens $youtube(response_format)]
  478. putserv "PRIVMSG $channel :$result"
  479. }
  480. }
  481. }
  482.  
  483. # This is triggered on !youtube commands.
  484. # Allows turning monitoring on or off by admins.
  485. # All other queries are interpreted as a youtube search.
  486. proc youtube_query {nick userhost handle channel largs} {
  487. global youtube botnick yt_search_ignore
  488.  
  489. # We get a list of arguments, join it to get rid of the curly braces..
  490. set args [join $largs]
  491.  
  492. if { [string length $args] == 0 } {
  493. if { [channel get $channel youtube] } {
  494. putserv "PRIVMSG $channel :Syntax: \002!youtube <search criteria>\002 - Search for a video showing the top $youtube(search_res_def) result(s)."
  495. putserv "PRIVMSG $channel :Syntax: \002!youtube +<number of results> <search criteria>\002 - Search for a video showing the top results. (Shows max $youtube(search_res_max) result(s).)"
  496. }
  497. if { [matchattr $handle +mno|+mno $channel] } {
  498. putserv "NOTICE $nick :Syntax: \002!youtube <on/off>\002 - Turn youtube link lookups on/off."
  499. }
  500. } elseif { [matchattr $handle +mno|+mno $channel] && ([string compare $args "on"] == 0 \
  501. || [string compare $args "off"] == 0) } {
  502. if { ![channel get $channel youtube] && [string compare $args "on"] == 0 } {
  503. channel set $channel +youtube
  504. putserv "NOTICE $nick :YoutubeTitleV2: activado en $channel"
  505. note "YoutubeTitleV2: Monitoring enabled by $nick for $channel."
  506. } elseif { [channel get $channel youtube] && [string compare $args "off"] == 0 } {
  507. channel set $channel -youtube
  508. putserv "NOTICE $nick :YoutubeTitleV2: disabled on $channel"
  509. note "YoutubeTitleV2: Monitoring disabled by $nick for $channel."
  510. }
  511. } elseif { [channel get $channel youtube] } {
  512. # Stores the number of search results to be fetched.
  513. set nbr $youtube(search_res_def)
  514.  
  515. # Check if the user requested a specific number of search results.
  516. if { [string first + $args] == 0 && [string is digit [string range [lindex $largs 0] 1 end]] == 1 } {
  517. set nbr [string range [lindex $largs 0] 1 end]
  518. set args [join [lrange $largs 1 end]]
  519. }
  520.  
  521. # Ensure no more then the maximum number of search results is fetched
  522. if {$nbr > $youtube(search_res_max) } {
  523. set nbr $youtube(search_res_max)
  524. }
  525.  
  526. # The magic number comes from the length of the string "cat".. ;)
  527. if { [string length $args] < 3 } {
  528. putserv "PRIVMSG $channel :Search criteria must be at least 3 characters long."
  529. return 0
  530. }
  531.  
  532. # First verify whether the user isn't on ignore..
  533. if { $youtube(search_int_min) > 0 } {
  534. # Don't just check for the existence of the key, but also verify the expiry time
  535. # set, in case for some reason the key didn't get removed when it should have been..
  536. if { [dict exists $yt_search_ignore $userhost] && [dict get $yt_search_ignore $userhost] > [unixtime] } {
  537. putserv "NOTICE $nick :YoutubeTitleV2: Please wait $youtube(search_int_min) seconds between searches."
  538. return 0
  539. }
  540.  
  541. # Add the user host to the YouTube search ignore list to ignore any queries for X seconds.
  542. dict set yt_search_ignore $userhost [expr [unixtime] + $youtube(search_int_min)]
  543. # Set a timer to remove the user host from the list after X seconds.
  544. utimer $youtube(search_int_min) [list dict unset yt_search_ignore $userhost]
  545. }
  546.  
  547. # Search a video...
  548. # Note that we have to do 2 requests: one to fetch search results (id)
  549. # and a second to get video details. This is caused by the YouTube API
  550. # not being capable of returning details in the search functions.
  551. if { [catch { set video_ids [search_video $args $nbr] } error ] } {
  552. note "Failed to find a video: $error (searching for '$args')."
  553. # If the reply contained an empty ID, we assume we found no video..
  554. } elseif { [llength $video_ids] == 0 } {
  555. putserv "PRIVMSG $channel :Unable to find a YouTube video matching search '$args'"
  556. } else {
  557. # Go over each video ID returned by our search query..
  558. set index 1
  559. foreach video_id $video_ids {
  560. # We have the video id, now find the properties..
  561. if { [catch {set tokens [fetch_props $video_id]} error] } {
  562. note "Failed to get video details: $error (searching for '$args' and found '$video_id')."
  563. # If the reply contained an empty ID, we assume we found no video..
  564. } elseif { [string length [dict get $tokens %­id%]] == 0 } {
  565. putserv "PRIVMSG $channel :Unable to fetch the video details of '$video_id' for the search result '$args'"
  566. } else {
  567. dict set tokens %botnick% $botnick
  568. dict set tokens %­poster% $nick
  569. dict set tokens %­query% $args
  570. dict set tokens %­res_nbr% $index
  571. dict set tokens %­res_tot% [llength $video_ids]
  572. # Rebuild the URL so we use a url shortener or force SSL
  573. # in all messages coming from us
  574. dict set tokens %­youtube_url% "$youtube(base_url)$video_id"
  575.  
  576. set result [string map $tokens $youtube(q_resp_format)]
  577. putserv "PRIVMSG $channel :$result"
  578. }
  579. incr index
  580. }
  581. }
  582. }
  583. }
  584.  
  585. ###############################################################################
  586.  
  587. note "YoutubeTitleV2 Version $YoutubeTitleVersion: loaded";
  588. hace 2 aÑos
Add Comment
Please, Sign In to add comment