Peux-tu être plus explicite ?
Ca ne marche pas lorsqu'on annonce une url youtube en https sur le canal, ou lorsqu'on modifie le script pour mettre:
tcl
set web(page) https://www.youtube.com
Pour le premier cas, ça m'étonne un peu vu qu'on se base sur la chaîne de caractère "watch?v=xxxxxxx" ou "youtu.be/xxxxxxx".
Après, si la vidéo est privée et donc accessible seulement pour un utilisateur logué, c'est normal.
C'est une erreur de ma part, je n'avais pas la bonne version du youtube.tcl du coup j'avais une erreur quand je postais une vidéo en https... Désolé ! ça fonctionne très bien !
J'viens vous présenter Zurl-0.01.tcl. Ce script fusionne la fonctionnalité d'un urltitle et d'un youtubetitle.
Les derniers posts de ce topic m'ont servi à personnaliser ce script. Les liens vers les sources sont dans la description. C'est le fruit de votre travail. = )
J'suis encore très novice et je n'ai fait qu'adapter les scripts à mes besoins en recherchant des codes simples et légés. Il y a encore quelques bugs que je n'arrive pas à corriger comme:
- La traduction des urls https pour le urltitle (ceux de youtube sont traduits mais pas toutes les autres)
- Empêcher le flood de la PL par le proc [mu] de youtitle (cela vient de la ligne
"set youtubeid "/watch?v=$youtubeid".
A part ça, le script est fonctionnel.
tcl
################ Zurl ################
############### Zurl.tcl is based on two grabbers urls titles scripts: ############### -The first one is a classic grabber who describe all (or most) of urls.############### (http://forum.eggdrop.fr/Titre-des-urls-diffusees-t-1331.html)############### - The second one is a youtube grabber. ############### (http://forum.eggdrop.fr/youtube-tiltle-t-1393.html)
############### So, the youtube (with rating, views, etc) and the classic grabber on ############### the same script was the point. Hope it'll be usefull.
############### JazZ (jazz@epiknet.org)
############### Easy to use; you only need to add the Zurl.tcl file to ../scripts/, ############### add the source path to the script in the eggdrop.conf and enjoy. set Zurlversion "0.01"
############### Packages & binding ############### package require httppackage require uri
bind PUBM - "*?://*?" check_url
bind PUBM - * mu
############### Proc "classic" ############### proc check_url {nick uhost handle chan text}{if{[regexp -- {([a-z0-9\-]+\://[a-z0-9\-]+\.[a-z0-9\-\.]+(?:/|(?:/[a-zA-Z0-9!#\$%&'\*\+,\-\.:;=\?@\[\]_~]+)*))}$text match url]}{set url [string map -nocase {"&""&"}$url]set token [geturl $url]set html_data [::http::data$token]
::http::cleanup$tokenregexp -all -nocase -- "<title>(.*)</title>"$html_data match title
if{![string match -nocase "*?/watch?v=*?"$url]&&![string match -nocase "*?://youtu.be*?"$url]}{;# than the classic grabber doesn't work on youtube's urls
putserv "PRIVMSG $chan :.:\[\002URL\002\]:. | $title | "
############### Uncomment the following lines to save titles, urls and linkers in your ../eggdrop/classics file ############### (classics will be automatically create)
# set bc [open classics a] # set classics ".:\[$a\] \($web(page)$youtubeid\) by \[$nick\]:." # puts $bc classics # close $bc}}return0}proc geturl {url args}{
array set URI [::uri::split$url];while{1}{set token [eval[listhttp::geturl$url]$args]if{![string match {30[1237]}[::http::ncode$token]]}{return$token}
array set meta [set${token}(meta)]if{![info exist meta(Location)]}{return$token}
array set uri [::uri::split$meta(Location)]
unset meta
if{$uri(host) == ""}{set uri(host)$URI(host)}set url [eval ::uri::join[array get uri]]}}
############### Proc Youtube ############### proc mu {nick uhost hand chan text}{set web(page)http://www.youtube.com
set watch [regexp -nocase -- {\/watch\?v\=([^\s]{11})}$text youtubeid]if{$watch == 0}{set watch [regexp -nocase -- {youtu\.be\/([^\s]{11})}$text a youtubeid]set youtubeid "/watch?v=$youtubeid";# the way this line was write is good but sends mistakes in PL. You can try with {} or something, ;# it won't get urls from youtube like https or youtu.be anymore. If you find a solution, ;# share your tips. By the way, it's almost perfect the way it is. }if{$watch&&$youtubeid!= ""}{
putlog "$web(page)$youtubeid"set agent "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1"set t [::http::config -useragent $agent]set t [::http::geturl"$web(page)$youtubeid" -timeout 30000]set data [::http::data$t]
::http::cleanup$tset l [regexp -all -inline -- {<meta name="title" content="(.*?)">.*?<span class="watch-view-count ">(.*?)</span>.*?<span class="likes-count">(.*?)</span>.*?\
<span class="dislikes-count">(.*?)</span>}$data]regexp{"length_seconds": (\d+),}$data"" length
foreach{black a b c d e}$l{set a [string map -nocase {\&\#39; \x27 & \x26 " \x22}$a]set b [string map [list \n ""]$b]set c [string map [list \n ""]$c]set d [string map [list \n ""]$d]set e [string map -nocase {\&\#39; \x27 & \x26 " \x22}$e]regsub -all {<.*?>}$a{} a
regsub -all {<.*?>}$b{} b
regsub -all {<.*?>}$c{} c
regsub -all {<.*?>}$d{} d
regsub -all {<.*?>}$e{} e
set b [string trim $b];# Some scotch to keep view at the right placeproc duration {s}{variable etube
set hours [expr{$s / 3600}]set minutes [expr{($s / 60)%60}]set seconds [expr{$s%60}]set res ""if{$hours!= 0}{append res "$hours hrs "}if{$minutes!= 0}{append res "$minutes\min "}if{$seconds!= 0}{append res "$seconds\sec"}return$res}
putserv "PRIVMSG $chan :.:\[\002YouTube\002\]:. | $a | [duration $length] | $b vues | + $c / - $d | "
############### Uncomment the following lines to save titles, urls and linkers in the ../eggdrop/backlistube file ############### (backlistube will be automatically create)
# set mt [open backlistube a] # set backlistube ".:\[$a\] \($web(page)$youtubeid\) by \[$nick\]:." # puts $mt $backlistube # close $mt }}}
putlog "\0033Zurl-$Zurlversion.tcl\003 loaded"
Correction
La regexp qui extrait les infos youtube
Optimisations
- Suppression d'un bind (il est illogique d'avoir de binds qui vont réagir à la même chose),
- C'est la procédure principale qui "choisit" le traitement approprié,
- l'affichage des infos youtube est sorti du foreach,
- la procédure duration est sortie de la procédure youtube
Ok je te remercie pour ta réponse en espérant que quelqu'un ce lance dans le correctif, je l'aurais bien fais mais je ne pense pas avoir le niveau nécessaire pour cela.
je viens de trouver une version qui fonctionne avec l API ils expliquent même comment obtenir le code API.
Mais j'obtiens une erreur. voici l'erreur :
[11:30:13] Tcl error [youtube_query]: wrong # args: should be "matchattr handle flags ?channel?"
et voici le code
tcl
############################################################################### # Name: Youtube Title V2 # Author: Jan Milants <viper@anope.org> # Version: 2.0 (28/08/2014) # Eggdrop Version: 1.6.x # Requires TCL version: 8.5 # Package dependencies: http, tls, json # Credits: Based on original YouTube Script # by jotham.read@gmail.com # Design inspiration from # youtube.tcl by Mookie. ############################################################################### # Description # ------------- # The script monitors text channels for links to Youtube. # When found, it will query the google server for details such as video title # and number of views of the youtube video and advertise the results in the channel. # The script also supports searching youtube with the command "!youtube <search text>" # or "!yt <search text>". In response, the search query will be passed on to the # youtube API and the best ranking result will be linked in channel. # # This script will be active on any channel it resides in with the "youtube" flag. # The flag can be set in the console with ".chanset #chan youtube" or with the # in channel command "!youtube on". Both commands only work for users with flag mno. # # Getting your own Google API key # --------------------------------- # This script uses the Google Youtube Data API V3, which requires an API key to # authorize access to the API and is used as basis for limiting request per day etc. # Instructions can be found on # https://developers.google.com/youtube/registering_an_application # Required steps in short: # 1. Go to the Google developers console https://console.developers.google.com # 2. Create a new project. Give it a name like 'eggdrop', doesn't matter much. # 3. When the project is loaded, select menu "APIs" under "APIs & auth" # 4. In the list of APIs, enable the "YouTube Data API v3". # 5. Select menu "Credentials" and click "Create new key". # 6. Select key type "server". # 7. Fill in the IP(s) or IP range from which the eggdrop bot will send # requests to google's servers. This is a whitelist, if the request # comes from a different IP, it will be rejected. # Note: If my-ip or my-hostname is configured in eggdrop.conf, they should # be entered here. # 8. You now have an API KEY; copy it to the config section below. # # !!! IMPORTANT !!! # When loading this script alongside other scripts which initiate web service calls, # ensure this script is loaded last! The script creates a handr for HTTPS connection # and sets the source IP to the my-ip or my-hostname from eggdrop.conf. # Most other scripts will not correctly enforce the source IP of requests and # can overwrite this scripts HTTPS handr. This results in connections coming from another # IP on the machine and may thus be rejected by the Google API Servers. # The typical error message logged would be "Error processing web service reply". # ############################################################################### # Changes: # 2.00 28/08/14 # Started development (Jan). # Almost complete rewrite most notable changes: # * Use the YouTube Data API V3. (Requires TLS support!) # * Strip out flat_json_decoder and use json & dict packages instead. # * Strip out tinyurl support. Better to use youtu.be in the response. # * Many more data elements supported in response format (possible by new API). # * Added possiblity to turn the script on/off on a channel by channel basis. # * Added ability to search youtube and return the first result. # 0.51 09/30/13 # Small correction for caps in url (but not video id) # 0.5 01/02/09 # Added better error reporting for restricted youtube content. # 0.4 10/11/09 # Changed title scraping method to use the oembed api. # Added crude JSON decoder library. # 0.3 02/03/09 # Fixed entity decoding problems in return titles. # Added customisable response format. # Fixed rare query string bug. ############################################################################### # # Configuration # ###############################################################################
# API key assigned to your Google account. # Sadly, everyone will have to register with Google and request their own API key. # An API key is linked to an IP or mask, so you will need to register one for your own. # Find detailed instructions above.set youtube(api_key)""
# Base URI for links to youtube videos. # Either use the normal youtube link or youtu.be for shorter URLs. # I'd recommend keeping the HTTPS to avoid exposing user data.set youtube(base_url)"https://www.youtube.com/watch?v=" #set youtube(base_url) "https://www.youtu.be/"
# Date/time format # The format to be used when showing dates, for example in publish date. # All times are in UTC. # # Available tokens: # %year% 4 digit year notation # %month% 2 digit month notation # %day% 2 digit day of the month notation # %hours% 2 digit hour notation on a 24hours basis # %minutes% 2 digit minutes notation # %seconds% 2 digit seconds notation # # Example: # "%day%/%month%/%year% %hours%:%minutes% UTC"set youtube(date_format)"%day%/%month%/%year% %hours%:%minutes% UTC"
# Response Formats # Template of the reply to be send to the channel showing the youtube video details. # A separate response can be set for replies to a pasted URL or to a query. # # Available tokens in the response format: # %botnick% Nickname of bot # %poster% Nickname of person who posted the youtube link # %youtube_url% URL to the youtube link (This may not be the exact same # URL that was posted since it's rewritten based on the format # above to ensure all links posted by the bot are HTTPS.) # %id% ID of the linked youtube video. # %author% Author/Uploader/channel of the video. # %title% Title of youtube link # %description% Description of the video. # (Note that this is generally a VERY long text!) # %published% Date & time the video was published. # %views% The number of times the video has been viewed. # %likes% The number of users who have "liked" the video. # %dislikes% The number of users who have "disliked" the video. # %length% Length of the video. # Tokens only available in the response to searches (q_resp_format): # %query% The original search string. # # Example: # "\002YouTube\002: %poster%: %youtube_url% - \"\002%title%\002\" (Uploaded by \"%author%\" on %published%) - Length: %length% - Views: %views% - Likes / Dislikes: %likes% / %dislikes%" # The template used when looking up a URL found in the channelset youtube(response_format)"\002YouTube\002: %poster%: %youtube_url% - \"\002%title%\002\" (Uploaded by \"%author%\" on %published%) - Length: %length% - Views: %views% - Likes / Dislikes: %likes% / %dislikes%" # The template used when replying to a search query.set youtube(q_resp_format)"\002YouTube\002: %poster%: Top result for searching '%query%': %youtube_url% - \"\002%title%\002\" (Uploaded by \"%author%\" on %published%) - Length: %length% - Views: %views% - Likes / Dislikes: %likes% / %dislikes%"
# The maximum number of characters from a youtube title to printset youtube(max_title_length)64
# The maximum number of characters from a youtube description to printset youtube(max_desc_length)128
############################################################################### # # Advanced Configuration # !!! DO NOT CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING !!! # ###############################################################################
# URLs of the youtube V3 APIset youtube(api_get)"https://www.googleapis.com/youtube/v3/videos"set youtube(api_search)"https://www.googleapis.com/youtube/v3/search"
# The groups of properties to be fetchedset youtube(api_part)"snippet,statistics,contentDetails"
# The fields from the selected property groups that are to be returnedset youtube(api_fields)"items(id,snippet(publishedAt,title,description,channelTitle),statistics,contentDetails(duration))"
# Maximum time in milliseconds to wait for youtube to respondset youtube(api_timeout)"30000"
# Pattern used to patch youtube links in channel public textset youtube(pattern){https{0,1}://.*youtu(?:\.be/|be\..*/watch\?(?:.*)v=)([A-Za-z0-9_\-])}
###############################################################################package require Tcl 8.5package require http2.7package require tls
package require json
# We need HTTPS support for the Google APIs.. # If local IP or host is configured in the main config, use it as the source # of the outgoing connections.if{[info exists {my-ip}] == 1&&[string length ${my-ip}]>0}{http::register https 443[list tls::socket -myaddr ${my-ip}]}elseif{[info exists {my-hostname}] == 1&&[string length ${my-hostname}]>0}{http::register https 443[list tls::socket -myaddr ${my-hostname}]}else{http::register https 443 tls::socket}set YoutubeTitleVersion "2.0"
setudef flag youtube
bind pubm - * public_youtube
bind pub - !youtube youtube_query
bind pub - !yt youtube_query
###############################################################################proc note {msg}{
putlog "% $msg"}
# Ensure strings are no longer then given length. This will cutoff the string # at the desired length and append '...'.proc shorten {text maxlen}{if{[string length $text]>[expr$maxlen - 1]}{set text [string range $text0[expr$maxlen - 4]]"..."}return$text}
# Convert an ISO8601 date into a more readable format..proc conv_iso8601_date {orig_date}{global youtube
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}if{[regexp$pattern$orig_date match year month day hours minutes hours_2 minutes_2 seconds milliseconds seconds_2 milliseconds_2]}{
# The hour and hour_2 variables are mutually exclusive, so we append the _2 variables to # the original ones to have fewer variables to work with.append hours $hours_2append minutes $minutes_2append seconds $seconds_2
# Put everything in a dictionary so we can have a configurable time format.set tokens [dict create]
dict set tokens %year%$year
dict set tokens %month%$month
dict set tokens %day%$day
dict set tokens %hours%$hours
dict set tokens %minutes%$minutes
dict set tokens %seconds%$secondsreturn[string map $tokens$youtube(date_format)]}else{error"Unable to process date value ($orig_date) returned by web service."}}
# Convert an ISO8601 duration into a more readable format..proc conv_iso8601_duration {duration}{set length ""set pattern {P(?:(\d )Y)?(?:(\d )M)?(?:(\d )D)?(?:T(?:(\d )H)?(?:(\d )M)?(?:(\d (?:\.\d )?)S)?)}if{[regexp$pattern$duration match years months days hours minutes seconds]}{if{[string length $years]>0}{append length $years Y " "}if{[string length $months]>0}{append length $months M " "}if{[string length $days]>0}{append length $days D " "}if{[string length $hours]>0}{append length $hours h " "}if{[string length $minutes]>0}{append length $minutes m " "}if{[string length $seconds]>0}{append length $seconds s " "}}else{error"Unable to process duration value ($duration) returned by web service."}return[string trim $length]}
###############################################################################
# Process the reply string of a video lookup from the Youtube API (JSON) and add the # data to a dictionary containing all tokens the user will be able to use in the template.proc read_props {json_blob}{global youtube
# Create an empty dictionary for the variables supported in the response format.set properties [dict create]
# Convert the JSON response to a dictionary.set reply [json::json2dict$json_blob]
# The web service returns a list of results, even though our query will always get 1. # So we have to take the first element from the list..if{![dict exists $reply items]}{error"Error processing web service reply."}else{set video [lindex[dict get $reply items]0]
# Check whether the variables we support in the response are present in the # reply from the web service. We check this one by one instead of assuming # they exist in case the API changes or someone messes with the requested fields. # Properties of the view we extract from reply..if{[dict exists $video id]}{
dict set properties %id%[dict get $video id]}else{
dict set properties %id%""}if{[dict exists $video snippet channelTitle]}{
dict set properties %author%[dict get $video snippet channelTitle]}else{
dict set properties %author%""}if{[dict exists $video snippet title]}{
dict set properties %title%[shorten "[dict get $video snippet title]"$youtube(max_title_length)]}else{
dict set properties %title%""}if{[dict exists $video snippet description]}{
dict set properties %description%[shorten "[dict get $video snippet description]"$youtube(max_desc_length)]]}else{
dict set properties %description%""}if{[dict exists $video snippet publishedAt]}{
dict set properties %published%[conv_iso8601_date [dict get $video snippet publishedAt]]}else{
dict set properties %published%""}if{[dict exists $video statistics viewCount]}{
dict set properties %views%[dict get $video statistics viewCount]}else{
dict set properties %views%""}if{[dict exists $video statistics likeCount]}{
dict set properties %likes%[dict get $video statistics likeCount]}else{
dict set properties %likes%""}if{[dict exists $video statistics dislikeCount]}{
dict set properties %dislikes%[dict get $video statistics dislikeCount]}else{
dict set properties %dislikes%""}if{[dict exists $video contentDetails duration]}{
dict set properties %length%[conv_iso8601_duration [dict get $video contentDetails duration]]}else{
dict set properties %length%""}}return$properties}
# Process the reply string of a search query to the Youtube API (JSON) and extract the # video id of the first result from the reply.proc read_searchres {json_blob}{global youtube
# Create an empty dictionary for the variables supported in the response format.set video_id ""
# Convert the JSON response to a dictionary.set reply [json::json2dict$json_blob]
# The web service returns a list of results, even though our query will always get 1. # So we have to take the first element from the list..if{![dict exists $reply items]}{error"Error processing web service reply."}else{set res [lindex[dict get $reply items]0]if{[dict exists $res id videoId]}{set video_id [dict get $res id videoId]}}return$video_id}
# Send a request to the youtube API to fetch the video details for # the video with the given ID.proc fetch_props {youtube_id}{global youtube
# Ensure an API key has been configured..if{[info exists youtube(api_key)] == 0 || [string length $youtube(api_key)] == 0}{error"An API key must be configured to access the Google web API!"}else{set query [http::formatQuery id $youtube_id key $youtube(api_key) \
part $youtube(api_part) fields $youtube(api_fields)]set response [http::geturl"$youtube(api_get)?$query" -timeout $youtube(api_timeout)]upvar #0$response state
if[expr[http::ncode$response] == 401]{error"Location contained restricted embed data."}else{set response_body [http::data$response]http::cleanup$responsereturn[read_props $response_body]}}}
# Find the video ID of the first match for the given search.proc search_video {criteria}{global youtube
# Ensure an API key has been configured..if{[info exists youtube(api_key)] == 0 || [string length $youtube(api_key)] == 0}{error"An API key must be configured to access the Google web API!"}else{set query [http::formatQuery type "video" q $criteria key $youtube(api_key) \
part "id" fields "items(id(videoId))" maxResults "1"]set response [http::geturl"$youtube(api_search)?$query" -timeout $youtube(api_timeout)]upvar #0$response state
if[expr[http::ncode$response] == 401]{error"Location contained restricted embed data."}else{set response_body [http::data$response]http::cleanup$responsereturn[read_searchres $response_body]}}}
###############################################################################
# This is triggered to analyse ever channel message for the presence of the youtube URL. # When one is found, the ID is extracted and passed on to get a list of the video properties. # Finally, this list is used to fill in the tokens in the user defined reply template.proc public_youtube {nick host hand chan args}{global youtube botnick
if{[channel get $chan youtube]&&[regexp -nocase -- $youtube(pattern)$args match video_id]}{if{[catch{set tokens [fetch_props $video_id]}error]}{
note "Failed to get video details: $error (querying '$video_id')" # If the reply contained an empty ID, we assume we found no video..}elseif{[string length [dict get $tokens%id%]] == 0}{
putserv "PRIVMSG $chan :Unable to find a youtube video with ID '$video_id'."}else{
dict set tokens %botnick%$botnick
dict set tokens %poster%$nick # Rebuild the URL so we use a url shortener or force SSL # in all messages coming from us
dict set tokens %youtube_url%"$youtube(base_url)$video_id"set result [string map $tokens$youtube(response_format)]
putserv "PRIVMSG $chan :$result"}}}
# This is triggered on !youtube commands. # Allows turning monitoring on or off by admins. # All other queries are interpreted as a youtube search.proc youtube_query {nick host hand chan args}{global youtube botnick
# We get a list of arguments, join it to get rid of the curly braces..set args [join$args]if{[string length $args] == 0}{if{[channel get $chan youtube]}{
putserv "PRIVMSG $chan :Syntax: \002!youtube <search criteria>\002 - Search for a video."}if{[matchattr $hand mno| mno $chan]}{
putserv "NOTICE $nick :Syntax: \002!youtube <on/off>\002 - Turn youtube link lookups on/off."}}elseif{[matchattr $hand mno| mno $chan]&&([string compare $args"on"] == 0 \
|| [string compare $args"off"] == 0)}{if{![channel get $chan youtube]&&[string compare $args"on"] == 0}{
channel set$chan youtube
putserv "NOTICE $nick :YoutubeTitleV2: enabled on $chan"
note "YoutubeTitleV2: Monitoring enabled by $nick for $chan."}elseif{[channel get $chan youtube]&&[string compare $args"off"] == 0}{
channel set$chan -youtube
putserv "NOTICE $nick :YoutubeTitleV2: disabled on $chan"
note "YoutubeTitleV2: Monitoring disabled by $nick for $chan."} # The magic number comes from the length of the string "cat".. ;)}elseif{[channel get $chan youtube]&&[string length $args]<3}{
putserv "PRIVMSG $chan :Search criteria must be at least 3 characters long."}elseif{[channel get $chan youtube]}{
# Search a video... # Note that we have to do 2 requests: one to fetch search results (id) # and a second to get video details. This is caused by the youtube API # not being capable of returning details in the search functions.if{[catch{set video_id [search_video $args]}error]}{
note "Failed to find a video: $error (searching for '$args')." # If the reply contained an empty ID, we assume we found no video..}elseif{[string length $video_id] == 0}{
putserv "PRIVMSG $chan :Unable to find a youtube video matching search '$args'" # We have the video id, now find the properties..}elseif{[catch{set tokens [fetch_props $video_id]}error]}{
note "Failed to get video details: $error (searching for '$args' and found '$video_id')." # If the reply contained an empty ID, we assume we found no video..}elseif{[string length [dict get $tokens%id%]] == 0}{
putserv "PRIVMSG $chan :Unable to fetch the video details of '$video_id' for the search result '$args'"}else{
dict set tokens %botnick%$botnick
dict set tokens %poster%$nick
dict set tokens %query%$args # Rebuild the URL so we use a url shortener or force SSL # in all messages coming from us
dict set tokens %youtube_url%"$youtube(base_url)$video_id"set result [string map $tokens$youtube(q_resp_format)]
putserv "PRIVMSG $chan :$result"}}}
###############################################################################
note "YoutubeTitleV2 Version $YoutubeTitleVersion: loaded";