mIRC Home    About    Download    Register    News    Help

Print Thread
Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
Off and on for the past few months I have been trying to figure out how to make a good song request system. Here is what I have found/planned so far:
1. As each user requests a song, it will be stored in a text file. (I forgot to add here, that it would be SUPER neat if I could somehow send these song requests straight from MIRC to my local webpage. Using AJAX I think I could intercept this data and make things work.)
2. Using my own local server I will set up a web page that will play these songs in a playlist (similar to nightbot). I have yet to study how to make a playlist with youtube links, but I am sure hoping it doesn't involve complicated code trying to find out if/when a song has finished. I should hope that there is a simple way to create a temporary playlist that automatically deletes a song once it has been played.

Here is where I need help. So far, I have been stuck on how to use this google api
http://gdata.youtube.com/feeds/api/videos/R0xoMhCT-7A

to determine if a youtube url is valid or not.

I don't want anything fancy. I have tried using all sorts of scripts online, but they either A. assume that you put a valid link in, and obviously return valid info on it or B. are a complicated mess that are meant to just give json data on a url.

All I need is a simple way to see if there is a 404 error, or a 200 "good to go" response. I should think this should be accomplished in less than 10 lines of code right?

Thanks for any help, I would not be here if I were not at wit's end.
Jon

Last edited by darthclide; 25/06/14 05:58 PM. Reason: wanted to make a point about using ajax
Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
I am still not sure how forums work when you "edit" a post (as in, does it "bump" it back up to the top), but I figured I would just send a reply with more details.

As you have probably guessed, I have a little programming experience, but still don't understand some of these advanced methods such as sockets.

I am a little worried from lack of a response. Meaning, even if all somebody did, was come in here and confirm something simple like this can be done, it would do wonders for my confidence. Even sending me to a tutorial on what I would need to check that validity of that gdata link. The silence makes me think this isn't as simple as I thought it was frown

Last edited by darthclide; 29/06/14 03:22 AM.
Joined: Jan 2004
Posts: 1,358
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,358
You can check out my sockets in this script:
https://gist.github.com/memnochxx/5676bef5707a8019f0ca

In general I define an alias to create a hash table and open a socket. The socket events use this hash table (as the same name as the socket) to get the data to be passed to the server. Then I define a signal to be called when the socket is done which then reads the header and data received.

twitch.topic is probably a good starting point.

Joined: Dec 2013
Posts: 779
N
Hoopy frood
Offline
Hoopy frood
N
Joined: Dec 2013
Posts: 779


Nillens @ irc.twitch.tv
Nillen @ irc.rizon.net
Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
based off your code this is what I have so far:
Code:
on @*:text:!song*:#:{
  if ($2 != $null) {
    song # $2-
  }
}
alias song {
  var %videoid = $gettok($2-,1,35)
  %videoid = $gettok(%videoid ,2-,61)
  var %chan = #$$1, %song = $2-
  var %sockname = song. $+ $ticks
  hfree -w %sockname | .hmake %sockname
  hadd %sockname request /feeds/api/videos/ $+ videoid
  if (%song != $null) {
    msg # %videoid
    hadd %sockname method GET
    hadd %sockname signal song.get
  }
  sockopen -e %sockname gdata.youtube.com 443
}
on *:signal:song.get:{
  var %err = $1, %sockname = $2, %header = $3, %data = $4

  if (* 200 OK iswm $read(%header,n,1)) msg Good Status: $json(%data,status)
  else msg Bad Could not get status.

  hfree -w %sockname
  if ($isfile(%header)) .remove %header
  if ($isfile(%data)) .remove %data
}



Yet the code never gets to song.get
I don't even know if I am doing this right. This socket stuff is way beyond me, and the tutorials people have mentioned don't help me personally for 2 reasons:

1. I am not creating this code for anyone else. As such, I don't care if it looks ugly. I just want it to get the job done.
2. I have yet to find a tutorial that explains in layman's terms what happens at every point of code. If what I want could be explained at every step in pseudo code, it would help me understand sockets much better.

Joined: Jan 2004
Posts: 1,358
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,358
Where are all the socket events?

Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
What do you mean? I thought copying your code and tweaking it would work? I took out your oauth and chan stuff because i was 90% sure it was twitch code that isn't needed for youtube.

Joined: Jan 2004
Posts: 1,358
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,358
It should, but I can't know where it's breaking without the full script - especially because you must have changed it. There's nothing inherently wrong with what you've posted here, assuming that status is a valid field in the json you receive.

Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
when you say "status is a valid field". What do you mean? From what I remember with json, it just returns a bunch of fields with their values. In this case, if the link is valid there would be fields like "title" "description" etc etc.

I simply thought that there would be 404 error if the link was invalid, and a 200 if there was success. That is all I want for now (to check if link is valid).

Here is the full script below. I don't know if I need the 3 aliases "download", "youtube", and "json" when the only thing I want is A. Is the youtube url valid? and B. Down the road, I want to return the video name.

A. and B. should take far less lines of code right?
Code:
; Thanks to FiberOptics for this nifty snippet ;)
; Requires the $download snippet can be found here: http://sephiroth.bounceme.net/forum/viewtopic.php?t=104
; No need to change anything normally
; Simply paste it to remote and you will get an echo after someone pasted a youtube uri
; if you wanna use it for a bot change the post alias to return $true
;
; Update: 21.01.2012
;  - added some errorchecking
;  - changed Wildmatch
;  - better parsing
;  - added youtu.be-links
alias -l post { return $true }

on *:TEXT:!requestsong*:#: {
  var %url = http://gdata.youtube.com/feeds/api/videos/$2
}
on @*:text:!song*:#:{
  if ($2 != $null) {
    song # $2-
  }
}
on *:text:!request *youtube*v=*:*: {
  var %xtwo = $gettok($1-,1,35)
  %xtwo = $gettok(%xtwo,2-,61)
  var %url = $wildtok($1-,*youtube.com/*v=*, 1, 32)
  if ($youtube(%url)) {
    tokenize 9 $ifmatch
    ; Author -> $1
    ; Duration -> $2
    ; Rating -> $3
    ; Date (last updated OR published) -> $4
    ; Preview Picture -> $5
    ; Title -> $6
    $iif($post,msg,echo $color(info)) $iif($chan,$chan,$nick) YouTube: $6 (Rating: $3 $+ ) from: $1 Date: $4 Duration: $2 Preview: $5 %url
  }
}
on *:text:!request *youtu.be*:*:{
  var %url = $wildtok($1-,http://youtu.be/*, 1, 32)
  if ($len(%url)) {
    %url = /?v= $+ $gettok(%url,3,47)
    if ($youtube(%url)) {
      tokenize 9 $ifmatch
      $iif($post,msg,echo $color(info)) $iif($chan,$chan,$nick) YouTube: $6 (Rating: $3 $+ ) from: $1 Date: $4 Duration: $2 Preview: $5 %url
    }
  }

}
alias song {
  var %videoid = $gettok($2-,1,35)
  %videoid = $gettok(%videoid ,2-,61)
  var %chan = #$$1, %song = $2-
  var %sockname = song. $+ $ticks
  hfree -w %sockname | .hmake %sockname
  hadd %sockname request /feeds/api/videos/ $+ videoid
  if (%song != $null) {
    msg # %videoid
    hadd %sockname method GET
    hadd %sockname signal song.get
  }
  sockopen -e %sockname gdata.youtube.com 443
}
on *:signal:song.get:{
  var %err = $1, %sockname = $2, %header = $3, %data = $4

  if (* 200 OK iswm $read(%header,n,1)) msg Good Status: $json(%data,status)
  else msg Bad Could not get status.

  hfree -w %sockname
  if ($isfile(%header)) .remove %header
  if ($isfile(%data)) .remove %data

}
alias -l urlencode return $regsubex($1-,/([^A-Z0-9])/gi,$+(%,$base($asc(\1),10,16)))
alias youtube {
  ; http://www.youtube.com/watch?v=B0fFDk2M0zE&feature=fvhl#cookie
  ; example: $youtube(...youtube.com/watch?v=vid)
  var %x = $gettok($1-,1,35) , %o = $null, %r = $null, %y = 0
  %x = $gettok(%x,2-,63)
  %y = $numtok(%x,38)
  while (%y) {
    %o = $gettok(%x,%y,38)
    if ($gettok(%o,1,61) == v) { %r = $gettok(%o,2,61) }
    dec %y
  }
  if (!$len(%r)) { return $false }
  else { %x = %r }
  if ($download(tmpfile,GET,http://gdata.youtube.com/feeds/api/videos/ $+ %x ,2)) {
    bread tmpfile 0 $lof(tmpfile) &bin
    var %string = $b(&bin,<author>)
    if ($regex(%string,/\<author\>\<name\>(.*)\<\/name\>/ig)) { var %author = $regml(1) }
    var %string = $b(&bin,<yt:duration)
    if ($regex(%string,/\<yt:duration seconds='([\d]+)'\/\>/ig)) { var %duration = $duration($regml(1),3) }
    var %string = $b(&bin,<gd:rating)
    if ($regex(%string,/average='([^']+)' max='([\d]+)'/ig)) { var %rating = $round($regml(1),3) }
    var %string = $b(&bin,<title)
    if ($regex(%string,/type='text'>([^<]+)/ig)) { var %title = $regml(1) }
    var %string = $b(&bin,<updated>)
    if ($regex(%string,/\<updated>([\d]{4})-([\d]{2})-([\d]{2})T([\d]{2}:[\d]{2})\:/ig)) { var %date = $regml(3) $+ . $+ $regml(2) $+ . $+ $regml(1) $regml(4) }
    else {
      var %string = $b(&bin,<published>)
      if ($regex(%string,/\<published>([\d]{4})-([\d]{2})-([\d]{2})T([\d]{2}:[\d]{2})\:/ig)) { var %date = $regml(3) $+ . $+ $regml(2) $+ . $+ $regml(1) $regml(4) }
    }
    var %preview = http://i.ytimg.com/vi/ $+ %x $+ /0.jpg
    if ($isfile(tmpfile)){!.remove tmpfile}
    if (!$len(%author)) var %author = n/a
    if (!$len(%duration)) var %duration = 00:00:00
    if (!$len(%date)) var %date = n/a
    if (!$len(%preview)) var %preview = n/a
    if (!$len(%title)) var %title = n/a
    if (!$len(%rating)) var %rating = n/a
    %x = $t(%author,%duration,%rating,%date,%preview,%title)
  }
  else { var %x = $false }
  if ($isfile(tmpfile)) { !.remove tmpfile }
  return %x
}
alias -l t { var %x = $0,%o | while (%x) { %o = $ [ $+ [ %x ] ] $+ $chr(9) $+ %o | dec %x } | return %o }
alias -l b { return $bvar($1,$bfind($1,1,$2).text,$iif($version > 6.31,4000,800)).text }
alias download {
  var %r = $(|,) return $false, %e = scon -r !echo $color(info) -a $!!download: Error -
  if (!$isid) %e this snippet can only be called as an identifier. %r
  if ($os isin 9598) %e this snippet requires Windows ME or higher. %r
  if ($version < 6) %e this snippet requires mIRC version 6.0 or higher. %r
  var %dir = $nofile($1), %file = $nopath($1), %method = $upper($2), %url = $3
  if (!$gettok(%dir,2,58)) { %dir = $mircdir $+ %dir }
  var %bit = $4, %headers = $iif($2 == get,$5,$6), %postdata = " $+ $5", %res
  if (* !iswm %file) %e you must specify a file to save the data to. %r
  if (%file != $mkfn(%file)) %e file %file contains illegal characters. %r 
  if (* !iswm %dir) %dir = $mircdir
  elseif (!$isdir(%dir)) %e no such folder %dir %r
  if (!$istok(get head post,$2,32)) %e method can only be GET, HEAD or POST. %r
  ;if (!$regex(%e,$3,/^\S+\.\S+\.\S+$/)) %e you didn't specify an url to download from. %r
  if ($2 != head) {
    if ($4 !isnum 1-3) %e bitmask should be a digit in range 1-3. %r 
    if ($2 == post) && (* !iswm $5) %e you didn't specify any post data. %r
    if (%headers) && (!$regsub(%e,%headers,/(\S+?): (.+?)(?=\s?\n|$)/g,"\1" $chr(44) "\2",%headers)) {
      %e bad header syntax. Correct -> Label: value seperated by $!!lf's %r
    }
  }
  var %file = $+(",%dir,%file,"), %id = $+(@download,$ticks,$r(1111,9999),.vbs), %a = aline %id
  if ((http://* !iswm $3) && (https://* !iswm $3)) { %url = http:// $+ $3 }
  .comopen %id wscript.shell 
  if ($comerr) %e could not open Wscript.Shell. %r
  write -c %file
  window -h %id
  %a on error resume next  
  %a sub quit $lf set http = nothing : set ado = nothing : wscript.quit $lf end sub
  %a sub errmsg 
  %a set fso = createobject("scripting.filesystemobject")
  %a set file = fso.createtextfile( %file ,true)
  %a file.write("Err number: " & err.number & " = " & err.description) : file.close
  %a set fso = nothing 
  %a quit
  %a end sub
  %a arr = array("winhttp.winhttprequest.5.1","winhttp.winhttprequest","msxml2.serverxmlhttp","microsoft.xmlhttp")
  %a i = 0 $lf while i < 4 and not isobject(http) : set http = createobject(arr(i)) : i = i + 1 : wend 
  %a if not isobject(http) then errmsg
  %a err.clear
  %a http.open $+(",%method,") , $+(",%url,") ,false
  %a http.setrequestheader "User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
  if (%headers) { tokenize 10 %headers | scon -r %a http.setrequestheader $* }
  if (%method == post) {
    %a http.setrequestheader "Content-Type","application/x-www-form-urlencoded" 
    %a http.send %postdata
  }
  else %a http.send
  %a if err then errmsg
  %a set ado = createobject("adodb.stream") 
  %a if not isobject(ado) then errmsg
  %a ado.open
  if (%bit != 2) {
    %a ado.type = 2 : ado.charset = "ascii" 
    %a ado.writetext "HTTP/1.1 " & http.status & " " & http.statustext,1
    %a ado.writetext http.getallresponseheaders,1 : ado.position = 0 
  }
  if (%bit != 1) %a ado.type = 1 : ado.read : ado.write http.responsebody 
  %a ado.savetofile $iif($mid(%file,3,1) != :,$qt($mircdir $+ $remove(%file,")),%file) ,2 : ado.close : quit
  savebuf %id $qt($mircdir $+ %id)
  close -@ %id
  .comclose %id $com(%id,run,1,bstr*,wscript.exe $qt($mircdir $+ %id),uint,0,bool,true)
  .remove %id 
  ; * This fixes one Line HTML Files with more than 4000 chars per line * (for example winamp shoutcast servers)
  .fopen file %file 
  .fseek -w file Err number:* = *
  var %pos = $fopen(file).pos
  .fclose file
  if ((%x < 0) || (%x >  10)) {
    if (!%pos){
    %res = $read(%file,t,1) 
    if (Err number:*=* iswm %res) || (!$file(%file)) %e $iif(%res,%res,no data could be retrieved) - %url %r
  }
  else {
    return $true
  }
  :error
  if ($com(%id)) .comclose %id
  if ($isfile(%id)) .remove %id
  if ($window(%id)) close -@ %id
  return $false
}
alias json {
  if ($isid) {
    ;name of the com interface declared so I don't have to type it over and over again :D
    var %c = jsonidentifier,%x = 2,%str,%p,%v

    ;if the interface hasnt been open and initialized, do it.
    if (!$com(%c)) {
      .comopen %c MSScriptControl.ScriptControl
      ;add two javascript functions for getting json from urls and files
      noop $com(%c,language,4,bstr,jscript) $com(%c,addcode,1,bstr,function httpjson(url) $({,0) y=new ActiveXObject("Microsoft.XMLHTTP");y.open("GET",encodeURI(url),false);y.send();return y.responseText; $(},0))
      noop $com(%c,addcode,1,bstr,function filejson (file) $({,0) x = new ActiveXObject("Scripting.FileSystemObject"); txt1 = x.OpenTextFile(file,1); txt2 = txt1.ReadAll(); txt1.Close(); return txt2; $(},0))
      ;add function to securely evaluate json
      noop $com(%c,addcode,1,bstr,function str2json (json) $({,0) return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(json.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + json + ')'); $(},0))
      ;add a cache for urls
      noop $com(%c,addcode,1,bstr,urlcache = {})
    }
    if (!$timer(jsonclearcache)) { .timerjsonclearcache -o 0 300 jsonclearcache }

    ;get the list of parameters
    while (%x <= $0) {
      %p = $($+($,%x),2)
      if (%p == $null) { noop }
      elseif (%p isnum || $qt($noqt(%p)) == %p) { %str = $+(%str,[,%p,]) }
      else { %str = $+(%str,[",%p,"]) }
      inc %x
    }
    if ($prop == count) { %str = %str $+ .length }

    ;check to see if source is file
    if ($isfile($1)) {
      if ($com(%c,eval,1,bstr,$+(str2json,$chr(40),filejson,$chr(40),$qt($replace($1,\,\\,;,\u003b)),$chr(41),$chr(41),%str))) { return $com(%c).result }
    }
    ;check to see if source is url
    elseif (http://* iswm $1) {
      ;if url is in cache, used cached data
      if ($com(%c,eval,1,bstr,$+(str2json,$chr(40),urlcache[,$replace($qt($1),;,\u003b),],$chr(41),%str))) { return $com(%c).result }
      ;otherwise, get data
      elseif ($com(%c,executestatement,1,bstr,$+(urlcache[,$replace($qt($1),;,\u003b),]) = $+(httpjson,$chr(40),$qt($1),$chr(41)))) {
        if ($com(%c,eval,1,bstr,$+(str2json,$chr(40),urlcache[,$replace($qt($1),;,\u003b),],$chr(41),%str))) { return $com(%c).result }
      }
    }
    ;get data from inputted json
    elseif ($com(%c,eval,1,bstr,$+(x=,$replace($1,;,\u003b),;,x,%str,;))) { return $com(%c).result }
  }
}
alias jsonclearcache { if ($com(jsonidentifier)) { noop $com(jsonidentifier,executestatement,1,bstr,urlcache = {}) } }
;-------------------;

;;;Basic Google Web Search Identifier;;;
;;;Only the first 8 results are retrieved;;;
;;;Syntax: $gws(<search params>,<result number>,<count|url|title|content>)
;;;Requires $json
alias gws {
  ;ensure a proper property (count, etc) is selected and result number is between 1 and 8
  if (!$istok(count url title content,$3,32) && $2 !isnum 1-8) { return }

  var %url = http://ajax.googleapis.com/ajax/services/search/web?q= $+ $1 $+ &v=1.0&safe=active&rsz=large

  ;check to see if results were found
  ;since results often come back with bolds, remove them
  if ($json(%url,responseData,results,0)) { return $iif($3 == count,$json(%url,responseData,cursor,estimatedResultCount).http,$remove($json(%url,responseData,results,$calc($2 - 1),$3).http,<b>,</b>)) }
}



Joined: Jan 2004
Posts: 1,358
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,358
None of my socket events are in there. You have a youtube and download alias which are not related to the song alias and song.get signal in any way.

Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
ah I think I see what you are talking about:
on *:sockopen:twitch.*
on *:sockread:twitch.*
on *:sockclose:twitch.*

Although I am not sure what to do about sockclose since you have it inside the "twitch.auth.request" which has nothing to do with youtube

Joined: Jan 2004
Posts: 1,358
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,358
Sockclose is called when the server closes the socket, which it should do automatically when it has finished sending data (if the connection: close header was specified).

I perform a sockclose myself in the twitch.auth.request because in that instance I'm acting as a server to receive the token request when the browser redirects to the redirect_uri, it's not necessary for you.

Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
Considering how long I am taking between replies, I am not expecting much, but I am hoping for some help on how to tweak the following to say "youtube link is valid" or "youtube link is not valid"

Code:
on @*:text:!song*:#:{
  if ($2 != $null) {
    demo $2
  }
}
alias demo {
  %videoid = $1
  %sockname = demo. $+ $ticks
  hfree -w %sockname | hmake %sockname
  hadd %sockname host gdata.youtube.com
  hadd %sockname port 80
  hadd %sockname request /feeds/api/videos/%videoid
  sockopen -e %sockname $hget(%sockname,host) $hget(%sockname,port)
}

on *:sockopen:demo.*: {
  var %<< = sockwrite -nt $sockname
  %<< GET $hget($sockname,request) HTTP/1.0
  %<< Host: $sock($sockname).addr
  %<< $crlf
}

on *:sockread:demo.*: {
  var %header, %content
  if (!$hget($sockname,header.complete)) {
    sockread %header
    while (%header != $null) {
      if (HTTP/* 2?? * iswm %header) { hadd $sockname following $true }
      elseif (HTTP/* 4?? * iswm %header) {
      }
      ;echo -ag %header
      sockread %header
    }
    if ($sockbr) hadd $sockname header.complete $true
  }

  if ($hget($sockname,header.complete)) {
    while ($sockbr) {
      sockread -f %content
      ;if (%content != $null) echo -ag %content
    }
  }
}

on *:sockclose:demo.*:{
  if ($hget($sockname,following)) { var %msg = Following }
  else { var %msg = Not following }

  if ($hget($sockname,chan)) { msg $v1 %msg }
  else { echo -ag %msg }

  hfree $sockname
}


Joined: Jun 2014
Posts: 52
D
Babel fish
OP Offline
Babel fish
D
Joined: Jun 2014
Posts: 52
*Update* I finally tweaked sephiroth's code to tell me if a youtube link is invalid or not. I really don't like hard-coding things to work and in this case it simply sees if "n/a" exists in the title. We will see if a youtube video comes along and somehow messes up on that piece of code, but it will suffice for now.

What I would like help on now is the following:
1. For the time being, if I am going to host this songrequest page on localhost, what language should I use? I was leaning towards a page with ajax since last time I used it on web development it was a great way to update the page on the fly without needing to refresh the whole page.
2. If I use ajax or something similar, can someone point me towards how I would use sockets to send the videoid to the page?

I should be able to get help from my past boss on how to make the playlist, but if I can at least get help on sending the id to my localhost page then that would be great.


Link Copied to Clipboard