[DE] YouTube Announcer (mSL)

By Kylar on Sep 25, 2020

Vorwort

Nachdem ich für AdiIRC ein Script gesucht habe, welches Informationen zu verlinkten YouTube Videos anzeigt, wurde hier ich fündig.
Allerdings ist das Script von nick1 (illhawkthat) in die Jahre gekommen und funktioniert nicht mehr richtig.
Deswegen habe ich ein Rewrite vorgenommen und meine eigene Version erstellt und auf das wesentliche (das Anzeigen von Informationen) reduziert.
Bei dieser Neuauflage handelt es sich allerdings nicht um eine perfekte Neuauflage des Scripts von
Ich habe mir die Sprache mSL erst ein paar Tage angeschaut und habe entsprechend noch nicht ihre Eigenheiten ganz im Griff.
Dennoch konnte ich bei meinen Tests keine großen Fehler feststellen.
Der Code ist mit reichlich Kommentaren versehen, zumindest am Anfang von den meisten Funktionen.

Beschreibung

Wie der Name schon fürchten lässt, handelt es sich um ein Script, das Informationen zu verlinkten YouTube Videos auf die eine oder andere Art ausgibt.
Die Ausgabe kann entweder im Channel/Query erfolgen oder nur für die eigene Sichtbarkeit über die Echo-Funktion.

Voraussetzung

Das Script ist rein in mSL geschrieben und greift auf keine COM Komponenten zu.
Dadurch entfällt die Voraussetzung, dass für die 64 bit Version von AdiIRC ein zuästzliches Programm (Script Control for 64 bit) installiert werden muss.
Allerdings muss, damit das Script funktioniert, ein Google API-Key beantragt werden, um auf die YouTube Data API v3 zugreifen zu können.
Sollte kein API-Key vorhanden sein, funktioniert das Script nicht.

Mit folgenden Clients wurde das Script getestet:

  • AdiIRC 3.8
  • mIRC 7.62

In neueren Versionen sollte das Script auch funktionieren.

Features

  • Einstellbar, welche Orte geparst werden sollen (Channel oder Queries)
  • Ausgabe kann auch über Echo nur für sich selbst erfolgen
  • Auswahl welche Links geparst werden sollen
    • youtube.com
    • youtu.be
    • yu2.be
  • Ausgabenachricht kann dank Platzhalter auf Wunsch angepasst werden
  • Einzelne Personen, Channel oder Server können ignoriert werden

Bekannte Fehler

  • Hauptdialog
    • Bei einem Klick auf ein Objekt im Dialog, werden die oberen Boxen leicht von den Tabs verdeckt (mIRC)

Installation

Allgemein

Das Script am besten in eine Text-Datei kopieren und als *.mrc Datei an einem für den Client zugänglichen Ort speichern.
Wenn das Script geladen wurde, kann mit dem Befehl /youtube_announcer das Script eingestellt werden.
Nachdem der Dialog geschlossen wurde, wird eine Datei (yta_settings.ini) im Ordner $mircdir angelegt.

mIRC

Über den Shortcut Alt+R den Scripteditor öffnen und auf den Tab "Remote" wechseln.
Anschließend mit Strg+L (oder über File->Load) die erstellte Datei laden.

AdiIRC

Über den Shortcut Alt+R den Scripteditor öffnen und anschließend mit Strg+L (oder über File->Load) die erstellte Datei laden.

Deinstallation

Allgemein

Mit dem Befehl /youtube_announcer deinstall kann das Script deaktiviert werden, ohne das es entladen werden
Ohne entladen wird das Event noch ausgeführt, aber bricht schon in den ersten Zeilen ab (durch fehlende Variablen).
Hinweis: Das Script ist nur so lange deaktiviert, bis /youtube_announcer aufgerufen wird. Durch den Aufruf werden nämlich alle Variablen neu geladen.

Vollständige Deinstallation

Um das Script vollständig zu deinstallieren, muss /youtube_announcer deinstall ausgeführt werden und anschließend die Datei entladen oder gelöscht werden.
In der Regel kann die Datei in den Clients im Editor unter dem Menüpunkt File -> Unload entladen werden und ein Aufruf von /youtube_announcer sollte nicht mehr möglich sein.
Zusätzlich kann die Datei am Speicherort entfernt werden.
Damit die Einstellugen persistent, auch über ein unload hinaus, erhalten bleiben, wird die Datei yta_settings.ini angelegt.
Die Datei kann in $mircdir (//echo -ag mIRC/AdiIRC Ordner: $mircdir) gefunden werden.

Der Code

; #-> Allgemeine Informationen <-#
; Name: YouTube Announcer
; Author: Kylar
; Date: 25.09.2020
; Version: 1.0.0 - Erster Release
; Beschreibung: YouTube Announcer tut genau das, was der Name vermuten/befürchten lässt.
; Das Script sucht aktiv in allen Channels (die nicht ignoriert werden sollen) nach YouTube Links und liefert, über die Google API, Informationen zum Video.
; Dabei kann die Ausgabe für sich selbst (über Echo) oder als MSG im Channel erfolgen.
;
; Voraussetzungen: AdiIRC in der Version 3.8 oder höher oder mIRC in der Version 7.62 oder höher.
;                               Einen Google API-Key für die YouTube Data API v3 (siehe https://developers.google.com/youtube/v3/getting-started)
;
; #-> Installation <-#
; Script entsprechend in AdiIRC/mIRC laden und den Befehl /youtube_announcer aufrufen, um das Script einzustellen.
; Nachdem die Einstellungen vorgenommen wurden, reagiert das Script entsprechend auf Nachrichten.
;
; #-> Deinstallation <-#
; Einfach den Befehl /youtube_announcer deinstall eingeben und das Script entfernt alle globalen Variablen.
; ACHTUNG: Die aktuellen Einstellungen werden in der yta_settings.ini gespeichert und beim erneuten aufrufen von /youtube_announcer geladen.
; Für eine vollständige Deinstallation den Befehl /youtube_announcer deinstall aufrufen, das Script und die yta_settings.ini löschen.

;;   ##############
;;  # Dialog/GUI #
;; ##############
alias youtube_announcer {
  if ( $0 == 0 ) {
    dialog -m yta_d_main yta_d_main
  } 
  else {
    if ( $lower($1) == deinstall || $lower($1) == uninstall || $lower($1) == deinstallation ) {
      yta_uninstall
    }
  }
}

; TODO Unter Nachricht einstellen, dass die Vorschau auch per Echo erfolgen kann (für Farbe usw.)
; Haupt Dialog zum einstellen des Scripts
Dialog yta_d_main {

  ;; Main 
  title "YouTube Announcer"
  ; -1 -1 setzt den Dialog in die Mitte vom Hauptfenster
  size -1 -1 200 150
  option dbu

  menu "About", 100
  ;  menu "Hilfe", 101

  ;; Tab Allgemeine Einstellen
  tab "Allgemeine Einstellungen", 1, 0 0 200 150
  box "Parsing", 10, 5 15 190 70, tab 1
  ; Abstand in der Höhe bei Check muss mindestens 8 sein
  check "Channel Nachrichten Parsen", 11, 10 24 76 8, tab 1
  check "Privat Nachrichten Parsen", 12, 10 32 70 8, tab 1
  check "YT-Infos nur über Echo ausgeben", 22, 95 24 88 8, tab 1
  text "Anbieter die geparst werden sollen", 13, 10 43 180 8, tab 1
  list 14, 10 52 180 28, tab 1 size extsel check multse vsbar

  box "API", 15, 5 90 190 50, tab 1
  text "Damit das Script Informationen über YouTube Videos abrufen kann,", 16, 10 99 180 8, nowrap tab 1
  text "wird ein API-Key von "17, 10 107 50 8, nowrap tab 1
  link "Google", 18, 62 107 18 8, tab 1
  text "benötigt.  Der Key wird auschließlich zum ", 19, 80 107 100 8, tab 1
  text "Abrufen der Videoinformationen verwendet." 20, 10 115 180 12, tab 1
  edit "", 21, 20 125 150 10, tab 1

  ;; Anpassen der Nachricht die ausgegeben wird
  tab "Nachrichten-Formatierung", 3, 0 0 200 150  
  box "Nachricht", 30, 5 15 190 57, tab 3
  edit "", 31, 10 24 180 10, tab 3 autohs
  text "Vorschau", 32, 10 36 100 8, tab 3
  edit "", 33, 10 44 180 10, tab 3 rich read autohs
  check "Vorschau als  Echo ausgeben?", 38, 10 58 80 8, tab 3
  box "Platzhalter", 34, 5 75 190 40 , tab 3
  text "Die folgenden aufgelisteten Zeichenfolgen werden automatisch ersetzt.", 35, 10 84 180 8, tab 3
  text "<duration>, <title>, <channeltitle>, <publishedat>, <favoritecount>", 36, 10 94 180 8, tab 3
  text "<viewcount>, <likecount>, <dislikecount>, <commentcount>", 37, 10 102 180 8, tab 3

  ;; Channels/Nicks die ignoriert werden sollen
  tab "Ignorieren", 4, 0 0 200 150
  text "Server, Channel und Nicknames eintragen, die ignoriert werden sollen.", 40, 5 15 190 12, tab 4

  box "Eingabe", 41, 5 30 190 37, tab 4
  text "Format: [network:][#]Ziel.", 42, 10 40 75 8, tab 4 
  edit "", 43, 10 50 150 10, tab 4
  button "Hinzfügen", 44, 163 50 30 10, tab 4

  box "Liste der zu ignorierenden Objekte", 45, 5 72 190 70, tab 4
  list 46, 10 82 153 55, tab 4 size extsel vsbar
  button "Entfernen", 47, 165 82 27 55, tab 4 multi
}

; About Dialog (zeigt momentan nur Basic-Informationen an)
dialog yta_d_about {
  title "About - YouTube Announcer"
  size -1 -1 100 70
  option dbu

  text "Script Name: YouTube Announcer", 1, 5 5 100 8
  text "Author: Kylar", 2 , 5 13 100 8
  text "Date: September 2020", 3, 5 21 100 8
  text "Kurzbeschreibung: Liefert Informationen zu erkannten YouTube Links", 4, 5 29 190 20
  text "Voraussetzung: YouTube/Goole API-Key", 5, 5 50 100 14
}

;;#
;; Dialog Events
;;#
; Settings laden und die Tabs mit Inhalt befüllen
on *:DIALOG:yta_d_main:init:0: {
  did -a yta_d_main 14 youtube.com
  did -a yta_d_main 14 yu2.be
  did -a yta_d_main 14 youtu.be

  ; Wenn keine Settings vorhanden sind, entsprechend die settings ini laden oder erstellen
  if ( !$var(%yta/settings/*)) {
    yta_load_config   
  }

  var %i = 1
  while ( %i <= $var(%yta/settings/*) ) {
    var %j = 1, %fp = $var(%yta/settings/*, %i) ,%sec = $token(%fp, $calc($numtok(%fp, 47) - 1), 47), %item = $token(%fp, $numtok(%fp, 47), 47)
    var %val = $var(%yta/settings/*, %i).value

    ; Liste der zu ignorierenden Ziele befüllen
    if (%item == list ) { 
      $iif(%val != $chr(7), yta_fill_ignorelist, noop)

    }
    ; Die Nachricht, die ausgegeben werden soll, befüllen 
    elseif ( %item == msg ) {
      $iif(%val != $chr(7), yta_fill_msg, noop ) 

    }
    ; API-Key Feld befüllen   
    elseif ( %item == apikey ) {
      $iif(%val != $chr(7), yta_fill_apikey, noop )

    }
    ; URLS in der Liste markieren
    elseif ( %item == urls ) {
      if ( %val != $chr(7) ) {
        var %j = 1
        while ( %j <= $numtok(%val, 44) ) {
          var %k = 1, %val1 = $token(%val, %j, 44)          
          while ( %k <= $did(14).lines ) {
            if ($did(14, %k).text == %val1) {
              did -s yta_d_main 14 %k
            }
            inc %k
          }
          inc %j
        }
      }
    } 
    ; Checkbox für die Ausgabe der über Echo
    elseif ( %sec == General && %item == echo ) {
      if ( %val == 1 ) {
        did -c $dname 22
      }
    }
    ; Checkbox, ob Channel-Nachrichten geparst werden sollen
    elseif ( %item == cmsg ) {
      if ( %val == 1 ) {
        did -c $dname 11
      }      

    } 
    ; Checkbox, ob Private-Nachrichten geparst werden sollen
    elseif ( %item == pmsg ) {
      if ( %val == 1 ) {
        did -c $dname 12
      }
    }
    ; Einstellung für die Ausgabe der Vorschau    
    elseif ( %sec == Message && %item == echo ) {
      if ( %val == 1 ) {
        did -c $dname 38
      }
    }
    inc %i
  }
}

; Einstellungen beim Verlassen des Dialogs in die ini schreiben
on *:DIALOG:yta_d_main:close:0: {
  yta_save_config
}

; API-Key in Variable speichern
on *:DIALOG:yta_d_main:edit:21: {
  set %yta/settings/General/apikey $did(21).text
}

; Verarbeitung der Click-Events
; Im Tab IgnoreList: Multiselektion kann nicht als ganzes entfernt werden, nur einzelne Ziele können entfernt werden.
on *:DIALOG:yta_d_main:sclick:*: {
  if ( $did == 11 ) {
    ; channel nachricht
    set %yta/settings/General/cmsg $did(11).state
  } 
  elseif ( $did == 12 ) {
    ; private nachricht
    set %yta/settings/General/pmsg $did(12).state
  }
  elseif ( $did == 22 ) {
    set %yta/settings/General/echo $did(22).state
  }
  elseif ( $did == 14 ) {
    ;listbox mit urls
    if ( $did(14, $did(14).sel ).cstate == 1 ) {
      set %yta/settings/General/urls $addtok($did(14, $did(14).sel).text, %yta/settings/General/urls, 44)
    } 
    else {
      set %yta/settings/General/urls $remtok(%yta/settings/General/urls, $did(14, $did(14).sel).text, 0, 44)
    }
  } 
  elseif ($did == 44) { ; Tab Ignorelist 
    ; Hinzufügen
    if ($len($did(43).text) > 0) {
      if ( (, !isin $did(43).text) && $regex($did(43).text, /^(?:\w+:)?#?[a-zA-Z0-9:#\|]+/) ) {
        set %yta/settings/IgnoreList/list $addtok($did(43).text, %yta/settings/IgnoreList/list, 44)
        did -r yta_d_main 43
        yta_fill_ignorelist
      }
    }
  }
  elseif ( $did == 47 ) { ; Tab Ignorelist 
    ; Entfernen
    if ( $len($did(46).seltext) > 0 ) {
      set %yta/settings/IgnoreList/list $remtok(%yta/settings/IgnoreList/list, $did(46).seltext, 0,44)
      did -r yta_d_main 46
      didtok yta_d_main 46 44 %yta/settings/IgnoreList/list
    }
  } 
  elseif ( $did == 38 ) {
    set %yta/settings/Message/echo $did(38).state
  }
  elseif ( $did == 18 ) {
    .url https://developers.google.com/youtube/v3/getting-started
  }
}

; Das Textfeld "Vorschau" mit den Inhalt aus "Nachricht" befüllen und 
; Platzhalter durch Dummy-Daten ersetzen
on *:DIALOG:yta_d_main:edit:31: {
  if ($len($did(31).text) > 0) {
    var %t1 = publishedAt $+ $chr(7) $+ title $+ $chr(7) $+ channelTitle $+ $chr(7) $+ duration $+ $chr(7) $+favoritecount $+ $chr(7) $+ viewcount $+ $chr(7) $+ likecount $+ $chr(7) $+ dislikecount  $+ $chr(7) $+ commentcount
    var %t2 = 2012-10-01T15:27:35Z $+ $chr(7) $+ A very special Title $+ $chr(7) $+ TheChan Nel $+ $chr(7) $+ PT7H3M33S $+ $chr(7) $+ 60 $+ $chr(7) $+ 1250 $+ $chr(7) $+ 1000 $+ $chr(7) $+ 250 $+ $chr(7) $+ 450

    ; Vorschau soll auch per Echo erfolgen
    if ( %yta/settings/Message/echo == 1 ) { 
      echo -ga $yta_replace_placeholder($did(31).text, %t1, %t2)
    } 
    did -ri yta_d_main 33 1 $yta_replace_placeholder($did(31).text, %t1, %t2)
  } 
  else {
    did -r yta_d_main 33
  }
  set %yta/settings/Message/msg $did(31).text
}

; About Dialog öffnen 
on *:DIALOG:yta_d_main:menu:100 {
  ; Diese Operation blockt die UI und das Fenster MUSS geschlossen werden
  noop $dialog(yta_d_about, yta_d_about)
}

;;#
;;  Helfer-Funktionen
;;#

; Liste der zu ignorierenden Ziele füllen
alias yta_fill_ignorelist {
  did -r yta_d_main 46

  var %i = 1 
  while ( %i <= $numtok(%yta/settings/IgnoreList/list, 44) ) {
    var %val = $token(%yta/settings/IgnoreList/list, %i, 44)
    did -a yta_d_main 46 %val
    inc %i
  }
}

; Wird beim Dialog-Start aufgerufen, um "Vorschau" und "Nachricht" zu befüllen
alias yta_fill_msg {
  if ( $len(%yta/settings/Message/msg) > 0 ) {
    did -r yta_d_main 31
    did -a yta_d_main 31 %yta/settings/Message/msg

    var %t1 = publishedAt $+ $chr(7) $+ title $+ $chr(7) $+ channelTitle $+ $chr(7) $+ duration $+ $chr(7) $+favoritecount $+ $chr(7) $+ viewcount $+ $chr(7) $+ likecount $+ $chr(7) $+ dislikecount  $+ $chr(7) $+ commentcount
    var %t2 = 2012-10-01T15:27:35Z $+ $chr(7) $+ A very special Title $+ $chr(7) $+ TheChan Nel $+ $chr(7) $+ PT7H3M33S $+ $chr(7) $+ 60 $+ $chr(7) $+ 1250 $+ $chr(7) $+ 1000 $+ $chr(7) $+ 250 $+ $chr(7) $+ 450

    did -ri yta_d_main 33  1 $yta_replace_placeholder($did(31).text, %t1, %t2)
  }
}

; Wird beim Dialog-Start aufgerufen, um das Feld "APIKEY" zu befüllen
alias yta_fill_apikey {
  if ( $len(%yta/settings/General/apikey) > 0 ) {
    did -r yta_d_main 21
    did -a yta_d_main 21 %yta/settings/General/apikey
  }
}

; Ersetzt im Text ($1) alle Platzhalter ($2) mit den enstprechenden Werten ($3)
; Die Funktion erwartet 3 Token
; $1 = Text in dem ersetzt werden soll
; $2 = Eine Tokenliste (Trennzeichen $chr(7)) mit Wörtern die Ersetzt werden sollen (ohne < und >)
; $3 = Eine Tokenliste (Trennzeichen $chr(7)) mit der gleichen Länge wie $2 und den entrechpenden Werten die eingesetzt werden sollen.
; Rückgabe: Der übergebene Text ($1) mit den ersetzten Platzhaltern oder bei Fehler den gleichen Text
; Beispiel: //echo -ag $yta_replace_placeholder(Der <title> ist von <channeltitle>., title $+ $chr(7) $+ channeltitle, TESTTITLE $+ $chr(7) $+ Channel Title ist Super!)
alias yta_replace_placeholder {
  var %msg = $1

  if ($isid && $0 == 3) {

    if ( $numtok($2, 7) == $numtok($2, 7) ) {
      var %i = 1 
      while ( %i <= $numtok($2, 7) ) {
        var %key = $lower($token($2, %i, 7)), %val = $token($3, %i, 7)

        if ( (%key != title) && (%key != channelTitle) ) {
          var %val $yt_placeholder_format(%val)
        }

        noop $regsub(%msg, /< $+ %key $+ >/gi, %val, %msg)
        inc %i
      }
    }

    return %msg
  }
}

; Helferfunktion die Zahlen (1000 wird zu 1 Tsd), Published-Datum (2012-10-01T15:27:35Z zu 01.10.2012) und Lauflänge (PT3D1H5M30S zu 03:01:05:30) umwandelt
; Zahlen werden nur bis Mrd umgewandelt, alles was größer ist, wird normal ausgegeben
; Zeit wird, bei Fehler und so weiter, als 00:00:00 ausgegeben
; TODO Funktion mathematisch aufarbeiten und nicht so einen Quark nutzen :P aber so lange es funktioniert?
alias yt_placeholder_format {
  if ($isid && $0 == 1) {
    if ( $1 isnum ) {
      var %i = 3, %j = 1, %suff = Tsd.Mio.Mrd

      while ( %i <= 9 ) {
        var %v = $round($calc($1 / (10^%i)), 2)

        if ( $len($int(%v)) <= 3 && $int(%v) > 0  ) {
          return %v $token(%suff, %j, 46)
        }

        inc %i 3
        inc %j
      }

    }
    elseif ( $lower($left($1, 2)) == $lower(PT) ) {
      var %t = $lower($mid($1, 3, $len($1)))
      var %d = 00, %h = 00, %m = 00, %s = 00

      while ( $len(%t) >= 1 ) {
        if ( $left(%t, 1) isnum ) {
          var %tmp = %tmp $+ $left(%t, 1)
        } 
        else {
          var  % $+ $left(%t, 1) $iif($len(%tmp) == 1, 0) $+ %tmp
          unset %tmp
        }
        var %t = $mid(%t, 2, $len(%t))
      }

      return $iif(%d != 00, %d $+ :) $+ $iif(%h != 00, %h $+ :, 00:) $+ $iif(%m != 00, %m $+ :, 00:) $+ %s
    }
    elseif ( $numtok($1, 84) == 2  ) {
      var %date = $token($1, 1, 84)
      return $token(%date, 3, 45) $+ . $+ $token(%date, 2, 45) $+ . $+ $token(%date, 1, 45)
    } 
  }

  return $1
}

; Überprüft, ob eines der angegebenen Argumente in der Ignorelist ist
; Folgende Angaben sind möglich:
; Wenn nur $1: $1 = Channel/Nickname/Server der geprüft wird
; Wenn $1 und $2: $1 = Server, $2 = Nickname/Channel der in Kombination geprüft werden soll
; Wenn $1, $2, und $3: $1 = Server, $2 = Channel und $3 = Nickname
; Rückgabe: $true wenn eins der übergebenen Argumente in der Liste gefunden wird, ansonsten $false
alias yta_is_in_ignorelist {
  if ( $isid ) {
    if ( $0 >= 1 ) {
      var %i = 1, %1 = $lower($1), %2 = $lower($2), %3 = $lower($3)
      while ( %i <=  $numtok(%yta/settings/IgnoreList/list, 44) ) {
        var %target = $lower($token(%yta/settings/IgnoreList/list, %i, 44))

        if ( %1 $+ : == %target || %1 == %target ) { 
          return $true
        } 
        elseif ( %2 != $null && ( %2 == %target || %1 $+ : $+ %2 == %target ) ) {
          return $true

        }
        elseif ( %3 != $null && (%3 == %target || %1 $+ : $+ %3 == %target) ) {
          return $true
        }
        inc %i
      }
    }  
    return $false
  }
}

; Testet, ob in $1 der Text nach möglichen URLS geparst werden soll.
; $1 muss entweder chan oder priv sein
; Rückgabe: $true wenn parsing aktiv sein soll, ansonsten $false
alias yta_is_parsing_active {
  if ( $isid ) {
    if ( ($1 == chan && %yta/settings/General/cmsg == 1) || ($1 == priv && %yta/settings/General/pmsg == 1) ) {
      return $true
    }
    return $false
  }
}

; Testet, ob $1 eine URL ist die aktiv abgefragt werden soll
; Rückgabe: $true wenn sie aktiv ist, ansonsten $false
alias yta_is_active_url {
  if ( $isid ) {
    var %i 1 
    while ( %i <= $numtok(%yta/settings/General/urls, 44) ) {
      if ( $1 == $token(%yta/settings/General/urls, %i, 44) ) {
        return $true
      }
      inc %i
    }
    return $false
  }
}

;; #
;; Konfiguration laden/speichern
;; Nur über das Dialog Event Init aufrufen!
;; #
alias yta_load_config {
  var %settings/General = cmsg pmsg echo urls apikey
  var %settings/Message = msg echo
  var %settings/IgnoreList = list

  var %i = 1
  while (%i <= $var(%settings/*)) {
    var %tmpk = $token($var(%settings/*, %i), 2, 47) 
    var %tmpv =  %settings/ [ $+ [ %tmpk ] ]
    var %j = 1

    while (%j <= $numtok(%tmpv, 32)) {
      var %item = $token(%tmpv, %j, 32)
      var %val = $readini($mircdir $+ yta_settings.ini, n, %tmpk, %item)

      set %yta/settings/ $+ %tmpk $+  / $+ %item $iif(%val == $chr(7), $null, %val)
      inc %j
    }

    inc %i
  }
}

alias yta_save_config {
  var %i = 1

  while ( %i <= $var(%yta/settings/*) ) {
    var %fp = $var(%yta/settings/*, %i)
    var %val = $var(%yta/settings/*, %i).value
    var %key = $token(%fp, $calc($numtok(%fp, 47) - 1), 47)
    var %item = $token(%fp, $numtok(%fp, 47), 47)

    ; Damit kein Fehler geworfen wird, representiert 7 (BEL) keinen Inhalt
    writeini $mircdir $+ yta_settings.ini  %key  %item  $iif(%val == $null, $chr(7), %val)

    inc %i
  }
}

;;   ######################################
;;  # Nachrichtenverarbeitung und Socket #
;; ######################################
;; <# Haupt-Event
; Reagiert auf Texte (Channel/Privat) die 
; https?://(www)?youtu(.be|be.com) oder https?://(www)?yu2.be beinhalten
; Abbruch des Events passiert in mehreren Stufen, weil nicht Daten
; sofort vorhanden sind (z.B. der tatsächliche URL wird erst im Regex ermittelt).
;; #>
on $*:TEXT:$(/https? $+ $chr(58) $+ \/{2}(w{3}\.)?(youtu\.?be(\.com)?|yu2.be)/Si):*: {
  ; Überprüfen, ob überhaupt parsing erlaubt ist
  if ( $chan != $null && !$yta_is_parsing_active(chan) ) {
    return $false
  }
  elseif ( $chan == $null && !$yta_is_parsing_active(priv) ) {
    return $false
  }

  ; Wenn das bearbeiten erlaubt ist, überprüfen dass auch kein Ziel (Server, Chan, Nick) ingoriert werden soll
  if ( !$yta_is_in_ignorelist($network, $iif($chan != $null, $chan, $nick), $iif($chan != $null, $nick)) ) {
    ; Folgendes regex soll die Video-ID suchen und das 1. Ergebnis speichern
    ; Den Regex kann man bestimmt schöner machen, aber er hat in meinen Tests funktioniert
    var %re = https?:\/{2}(?:w{3}\.)?((?:youtu\.?be(?:\.com)?|yu2.be))\/(?=watch\?v\=([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+))
    if ( $regex(yta_re_match, $1-, / $+ %re $+ /Si) > 0 ) {
      var %vid = $regml(yta_re_match, 2), %host = $regml(yta_re_match, 1)
      ; Host/URL kann erst ab hier geprüft werden
      ; Ist die URL nicht Aktiv (Checkbox im UI) dann wird das Event hier beendet
      if ( !$yta_is_active_url(%host) ) {
        return $false
      }
      ; Ticks sind ms seit systemstart
      var %tick $ticks

      ; Um Spam zu verhindern, nur alle 30 Sekunden ein Video für Chan/Nick abfragen
      if ( $calc(%tick -  [ % $+ yta/spamprot/ $+ [ $network ]  $+  [ $iif($chan != $null, $chan, $nick) ] $+ /tick ] ) >= 30000 ) {
        set %yta/spamprot/ $+ $network $+ $iif($chan != $null, $chan, $nick) $+ /tick %tick

        ; Spamprot und request Variablen nach 30 Sekunden entfernen
        .timer $+ yta/timers/ $+ $network $+ $iif($chan != $null, $chan, $nick) 1 30  yta_request_cleanup $network $+ $iif($chan != $null, $chan, $nick)

        ; Socket öffnen und Informationen als mark speichern
        sockopen -e yta/sockets/ $+ %tick googleapis.com 443
        sockmark yta/sockets/ $+ %tick $network $+ , $+ $iif($chan != $null, $chan, $nick) $+ , $+ %vid

      }
    } 
  }
}

;; <# Socket Logik
; Im folgendem Abschnitt befindet sich die Logik für den Umgang mit den geöffneten Sockets.
; Dabei gibt es zwei Hauptevents die bearbeitet werden.
; Beim öffnen wird eine HTTP Anfrage an den googleapis Server geschickt und die Markierung vom Socket in die Request-Variable geschrieben.
; Im Lesevorgang werden die erhaltenen Daten verarbeitet, in die Request-Variable geschrieben und die Ticknummer an die Funktion yta_send_message übergeben
;; #>
on *:SOCKOPEN:yta/sockets/*: {
  ; Daten für das GET  Request zusammen tragen
  var %apikey %yta/settings/General/apikey
  var %vid $token($sock($sockname, 1).mark, 3, 44)

  var %tick $token($sockname, $numtok($sockname, 47), 47)

  ; Wenn eines von beiden nicht abgerufen werden kann, socket schließen
  if ( %apikey == $null || %vid == $null) {
    unset %yta/ytrequests/ $+ %tick $+ /*
    sockclose $sockname
    return $false
  }

  ; GET Request zusammensetzen
  var %get /youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics $+ &id= $+ %vid $+ &key= $+ %apikey

  ; HTTP Anfrage senden
  sockwrite -n $sockname GET %get HTTP/1.1
  sockwrite -n $sockname Host: www.googleapis.com
  sockwrite -n $sockname User-Agent: mSL YouTube Announcer
  sockwrite -n $sockname Accept: application/json
  sockwrite -n $sockname

  set %yta/ytrequests/ $+ %tick $+ / $+ network $token($sock($sockname, 1).mark, 1, 44)
  set %yta/ytrequests/ $+ %tick $+ / $+ dest $token($sock($sockname, 1).mark, 2, 44)
  set %yta/ytrequests/ $+ %tick $+ / $+ vid  $token($sock($sockname, 1).mark, 3, 44)

}

; TODO Eventlogik umschreiben, so das Hashtables verwendet werde
; Durch filtern von Elementen die ersetzt werden, ensteht ein Chaos aus IF/ELSIF Verzweigungen.
; Deswegen wäre ein Rewrite mit Hashtables vielleicht sinnvoll, um alle Elemente vom JSON zu speichern.
on *:SOCKREAD:yta/sockets/*: {
  var %tick $token($sockname, $numtok($sockname, 47), 47)
  var %line

  sockread %line

  ; HTTP Status-Code abfragen und entsprechend fortfahren oder abbrechen  
  if ( HTTP/1.1 isin %line ) {
    if ( $token(%line, 2, 32) != 200 ) {
      unset %yta/ytrequests/ $+ %tick $+ /*
      sockclose $sockname
      return $false
    }

  }
  elseif ( "publishedAt" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ publishedat %val

  } 
  elseif ( "title" isin %line && %yta/ytrequests/ [ $+ [ %tick ] $+ /title ] == $null ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ title %val

  } 
  elseif ( "channeltitle" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ channeltitle %val

  } 
  elseif ( "duration" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ duration %val    

  } 
  elseif ( "viewcount" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ viewcount %val    

  } 
  elseif ( "likecount" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ likecount %val    

  } 
  elseif ( "dislikecount" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ dislikecount %val    

  } 
  elseif ( "favoritecount" isin %line ) {
    var %val $token($yta_json_keyval_token(%line), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ favoritecount %val

  } 
  elseif ( "commentCount" isin %line ) {
    ; Quick and Dirty: Einfach ein Komma am Ende hinzufügen, weil sonst das Regex nicht greift
    var %val $token($yta_json_keyval_token(%line $+ $chr(44)), 2, 7)
    set %yta/ytrequests/ $+ %tick $+ / $+ commentcount %val    

    ; Comment Count ist das letzte Element das interessant ist für dieses Script
    sockclose $sockname
    yta_send_msg %tick
  } 
}

; Wird ausgeführt, wenn die Gegenseite ein Socket beendet
; Entsprechend, damit sich nicht zu viele globale Variablen ansammeln, ein unset versuchen
on *:SOCKCLOSE:yta/sockets/*: {
  var %tick $token($sockname, $numtok($sockname, 47), 47)
  unset %yta/ytrequests/ $+ %tick $+ /*
}

;; <#
;; Helfer Funktionen und Events
;; #>

; Parst die Zeichenfolge und teilt diese in Key:Val auf (Token, Trennzeichen 7) (Quick and Dirty Version)
; Argument $1: Zeichenfolge im Format \s+"<Key>":\s"<Val>",
; Rückgabe: Key und Val als Token oder nichts bei Fehler
; TODO Regex umschreiben, so das es auch greift, wenn kein Komma am Ende ist (letzte Element in einer Liste in JSON)
alias yta_json_keyval_token {
  if ( $isid ) {
    if ( $regex(yta_test, $1, /^\s+"(.*?)": "(.*?)" $+ $chr(44)$/) == 1 ) {
      var %key $regml(yta_test,1)
      var %val $regml(yta_test,2)
      return %key $+ $chr(7) $+ %val
    }

    return $null
  }
}

; Wraper, um einfacher auf die Request-Variable zugreifen zu können
; Argument $1: Tick Nummer vom Request
; Rückgabe: Inhalt der Request-Variable oder $null
; Beispiel: echo -ga Title: $yta_request_result(<tick>).title
alias yta_request_result {
  if ( $isid ) {
    if ( $var(%yta/ytrequests/ [ $+ [ $1 ] $+ ] /*) > 0 ) {
      return %yta/ytrequests/ [ $+ [ $1 ] $+ / $+ [ $prop ] ]
    }
    return $null
  }
}

; Gibt die eingestellte Nachricht am Abfrageort aus oder per Echo im aktiven Fenster
; Argument $1: yta request Tick Nummer
; Die Funktion erwartet als 1. Argument den Namen der globalen Variable 
; für den Request der ausgegeben werden soll
alias yta_send_msg {
  var %placeholders publishedAt $+ $chr(7) $+ title $+ $chr(7) $+ channelTitle $+ $chr(7) $+ duration $+ $chr(7) $+ favoritecount
  var %placeholders %placeholders $+ $chr(7) $+ viewcount $+ $chr(7) $+ likecount $+ $chr(7) $+ dislikecount  $+ $chr(7) $+ commentcount

  ; Replace mit dem Wraper befüllen
  var %replace $yta_request_result($1).publishedat $+ $chr(7) $+ $yta_request_result($1).title $+ $chr(7) $+ $yta_request_result($1).channeltitle 
  var %replace %replace $+ $chr(7) $+ $yta_request_result($1).duration $+ $chr(7) $+ $yta_request_result($1).favoritecount $+ $chr(7) $+ $yta_request_result($1).viewcount
  var %replace %replace $+ $chr(7) $+ $yta_request_result($1).likecount $+ $chr(7) $+ $yta_request_result($1).dislikecount $+ $chr(7) $+ $yta_request_result($1).commentcount

  var %dst $yta_request_result($1).dest
  var %net $yta_request_result($1).network
  if ( %yta/settings/General/echo == 1 ) {
    echo -gf %dst $yta_replace_placeholder(%yta/settings/Message/msg, %placeholders, %replace)
  } 
  else {
    .msg %dst $yta_replace_placeholder(%yta/settings/Message/msg, %placeholders, %replace)
  }
}

; Entfernt die Spamprotect Variable und Request Variable
; Spamprotect ist fest auf 30 Sekunden einprogrammiert und wenn in der Zeit keine Rückmeldung gekommen ist, 
; kann auch die requests Variable verworfen werden
; Argument $1: Spamprotect Variable Identifikation
alias yta_request_cleanup {
  var %tick %yta/spamprot/ [ $+ [ $1 ]  $+ /tick ]

  unset %yta/spamprot/ [ $+ [ $1 ] $+ /* ]
  unset %yta/ytrequests/ [ $+ [ %tick ] $+ /* ]
}

; Settings in die INI schreiben, Timer und Sockets anhalten und globale Variables löschen
alias yta_uninstall {
  yta_save_config
  sockclose yta/sockets/*

  var %i 1

  while ( %i <= $timer(0) ) {
    var %tname $timer(%i)

    if ( yta/timers/ isin %tname ) {
      .timer $+ %tname off
    }

    inc %i
  }

  unset %yta/*

  echo -ag - YouTube Announcer - Das Script ist nun deaktiviert und sollte auf keine YouTube Links mehr reagieren.
}

; Wenn das Script entladen wird, uninstall ausführen
on *:UNLOAD: {
  yta_uninstall
}

Comments

Sign in to comment.
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.