From 6efab8ca782074c23caf36b638811fa16389bff4 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Sun, 3 Dec 2017 18:15:58 +0100 Subject: [PATCH 1/5] Rubocop --- tweetFM.rb | 297 ++++++++++++++++++++++++++--------------------------- 1 file changed, 148 insertions(+), 149 deletions(-) diff --git a/tweetFM.rb b/tweetFM.rb index 284e2d7..1053b8d 100644 --- a/tweetFM.rb +++ b/tweetFM.rb @@ -1,195 +1,194 @@ # dHdlZXRGTSB2NCBieSBkYXNpbmtpbmcgLSBtYWRlIGluIDIwMTYtMTcgd2l0aCA8Mw== -@version = "tweetFM_v4" +@version = 'tweetFM_v4' require 'yaml' require 'twitter' require 'lastfm' require 'oauth' -OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE #only needed for some ruby installations on windows, when you get a certificate error (fuck that) +OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE # only needed for some ruby installations on windows, when you get a certificate error (fuck that) -#####twitter_auth##### -@Twitter = Twitter::REST::Client.new do |config| - config.consumer_key = "4iTHA7VaA85qX0gaIT6fskn9f" #wooooooah! api keys! - config.consumer_secret = "3GQIVok9vUqob30DfQlghKLM7oACHqKaJtI1YMi90LfKI7a1KT" #those are public anyways, so it doesn't matter posting them publicly. :) +# ####twitter_auth##### +@Twitter = Twitter::REST::Client.new do |config| + config.consumer_key = '4iTHA7VaA85qX0gaIT6fskn9f' # wooooooah! api keys! + config.consumer_secret = '3GQIVok9vUqob30DfQlghKLM7oACHqKaJtI1YMi90LfKI7a1KT' # those are public anyways, so it doesn't matter posting them publicly. :) end -#####twitter_auth_end##### +# ####twitter_auth_end##### -#####lastfm_auth##### -@lastfm = Lastfm.new("d40320e36eca2707150f55723630436e", "aff6f8a58d4ad1a937e0128a83dec486") #especially those, because you can't create an app on last.fm for MONTHS now. you're welcome. -#####lastfm_auth_end##### +# ####lastfm_auth##### +@lastfm = Lastfm.new('d40320e36eca2707150f55723630436e', 'aff6f8a58d4ad1a937e0128a83dec486') # especially those, because you can't create an app on last.fm for MONTHS now. you're welcome. +# ####lastfm_auth_end##### def setup - if File.file?("config.yml") == true then #check for existing config - $config = { #opening the hash + if File.file?('config.yml') == true # check for existing config + $config = { # opening the hash - }.merge(YAML.load_file File.expand_path '../config.yml', __FILE__) #merging the existing config to check it's contents + }.merge(YAML.load_file(File.expand_path('../config.yml', __FILE__))) # merging the existing config to check it's contents - if $config[:revision] != 1 then #search for revision. this procedure is futureproof by increasing the number! so smart!! - begin #older versions of tweetFM didn't have this config entry, so it will directly identify those configs - puts "" #those older versions use other keys and general entry names, so we want them gone. + if $config[:revision] != 1 # search for revision. this procedure is futureproof by increasing the number! so smart!! + begin # older versions of tweetFM didn't have this config entry, so it will directly identify those configs + puts '' # those older versions use other keys and general entry names, so we want them gone. puts "Welcome to #{@version}! Looks like your update was successful, but we're not done yet." - puts "Your existing configuration is based on an older installation of tweetFM." - puts "A new configuration will be created, but before that, we need to delete the old one." - puts "If you have any emotional connection to it, create a backup now." + puts 'Your existing configuration is based on an older installation of tweetFM.' + puts 'A new configuration will be created, but before that, we need to delete the old one.' + puts 'If you have any emotional connection to it, create a backup now.' puts "When you're done, or you don't care, press enter." - stub = $stdin.gets.strip #wait for enter press - File.delete("config.yml") #delete old config - $config = {} #zero the variable - setup #rerun setup for configuring the new config file - end #yo dawg, i heard you like configurations - else #config is found which is up-to-date. it's configurations will be set + stub = $stdin.gets.strip # wait for enter press + File.delete('config.yml') # delete old config + $config = {} # zero the variable + setup # rerun setup for configuring the new config file + end # yo dawg, i heard you like configurations + else # config is found which is up-to-date. it's configurations will be set begin - @Twitter.access_token = $config[:twitter_token] #adding twitter tokens from the valid config + @Twitter.access_token = $config[:twitter_token] # adding twitter tokens from the valid config @Twitter.access_token_secret = $config[:twitter_token_secret] - @lastfmuser = $config[:lastfm_user] #and the lastfm-username for parsing the latest scrobbles - if $config[:url] == true then #resetting the url in the profile with every start of tweetFM, heheheh - @Twitter.update_profile(:url => "https://github.com/dasinking/tweetFM/") + @lastfmuser = $config[:lastfm_user] # and the lastfm-username for parsing the latest scrobbles + if $config[:url] == true # resetting the url in the profile with every start of tweetFM, heheheh + @Twitter.update_profile(url: 'https://github.com/dasinking/tweetFM/') end end end - else #o fuc, we need to setup - puts "" - puts "Welcome, new user of tweetFM!" + else # o fuc, we need to setup + puts '' + puts 'Welcome, new user of tweetFM!' puts "Before we can start spamming you and your friends' timeline, we need to configure some things." puts "It won't take long!" - $config = {} #opening the hash for incoming entries - #it's an hash, because we'll save those settings to an external file later. it's easier like that. - #####twitter_auth##### - puts "" - puts "First we need access to Twitter." - consumer = OAuth::Consumer.new(@Twitter.consumer_key,@Twitter.consumer_secret, :site => "https://api.twitter.com") #define where to send the request and it's parameters - request_token = consumer.get_request_token(:oauth_callback => @callback_url) #requesting and saving first oauth answer - - url = request_token.authorize_url(oauth_callback: @callback_url) #saving the auth url separately - - puts "Open this URL in a browser: #{url}" - pin = '' #init pin variable (zeroing) - until pin =~ /^\d+$/ #loop for typing in the auth pin - print "Enter PIN => " - pin = $stdin.gets.strip #saving pin - end + $config = {} # opening the hash for incoming entries + # it's an hash, because we'll save those settings to an external file later. it's easier like that. + # ####twitter_auth##### + puts '' + puts 'First we need access to Twitter.' + consumer = OAuth::Consumer.new(@Twitter.consumer_key, @Twitter.consumer_secret, site: 'https://api.twitter.com') # define where to send the request and it's parameters + request_token = consumer.get_request_token(oauth_callback: @callback_url) # requesting and saving first oauth answer + + url = request_token.authorize_url(oauth_callback: @callback_url) # saving the auth url separately + + puts "Open this URL in a browser: #{url}" + pin = '' # init pin variable (zeroing) + until pin =~ /^\d+$/ # loop for typing in the auth pin + print 'Enter PIN => ' + pin = $stdin.gets.strip # saving pin + end - @access_token = request_token.get_access_token(oauth_verifier: pin) #requesting the tokens with the auth pin and saving it + @access_token = request_token.get_access_token(oauth_verifier: pin) # requesting the tokens with the auth pin and saving it - $config[:twitter_token] = @access_token.token #defining the tokens in the config - $config[:twitter_token_secret] = @access_token.secret #like that, we need to reload setup in the end, so it defines the tokens + $config[:twitter_token] = @access_token.token # defining the tokens in the config + $config[:twitter_token_secret] = @access_token.secret # like that, we need to reload setup in the end, so it defines the tokens - if @Twitter.user("dasinking").id == 78006580 then #test whether or not i can access the api - puts "" - puts "Successfully logged into Twitter!" #although it's basically impossible to get to this step without a valid auth - else - puts "" #but i already programmed it so yeah - puts "somethings wrong with the auth process wtf" #all it does is requesting the user id of my profile and checking it - puts "that should be impossible actually" #technically it's not even a good test, as the user id is requestable over public api - setup #so maybe i'll scrap this later on or improve it, we'll see - end - #####twitter_auth_end##### - - #####lastfm username##### - puts "" - puts "Now, enter your last.fm-username:" - username = '' #init username variable (zeroing) - print "Username => " - username = $stdin.gets.strip #get input and save into var - $config[:lastfm_user] = username #saving username into config - #####lastfm username_end##### - - #####source code link y/n##### - puts - puts "tweetFM is free and open source, so it would be really nice of you to link the GitHub repository in your profile." - puts "Do you want me to do this for you? (y/n)" - link = '' #init username variable (zeroing) - - print "" - link = $stdin.gets.strip #saving username - - if link == "n" then #when they type anything else than no it'll change the url #dickmove - $config[:url] = false - else - $config[:url] = true - end - #####source code link y/n_end##### + if @Twitter.user('dasinking').id == 78_006_580 # test whether or not i can access the api + puts '' + puts 'Successfully logged into Twitter!' # although it's basically impossible to get to this step without a valid auth + else + puts '' # but i already programmed it so yeah + puts 'somethings wrong with the auth process wtf' # all it does is requesting the user id of my profile and checking it + puts 'that should be impossible actually' # technically it's not even a good test, as the user id is requestable over public api + setup # so maybe i'll scrap this later on or improve it, we'll see + end + # ####twitter_auth_end##### + + # ####lastfm username##### + puts '' + puts 'Now, enter your last.fm-username:' + username = '' # init username variable (zeroing) + print 'Username => ' + username = $stdin.gets.strip # get input and save into var + $config[:lastfm_user] = username # saving username into config + # ####lastfm username_end##### + + # ####source code link y/n##### + puts + puts 'tweetFM is free and open source, so it would be really nice of you to link the GitHub repository in your profile.' + puts 'Do you want me to do this for you? (y/n)' + link = '' # init username variable (zeroing) + + print '' + link = $stdin.gets.strip # saving username + + if link == 'n' # when they type anything else than no it'll change the url #dickmove + $config[:url] = false + else + $config[:url] = true + end + # ####source code link y/n_end##### - #####create the config file##### - $config[:revision] = 1 - File.open "config.yml", 'w' do |f| #save contents of the config hash - f.write $config.to_yaml #... in yaml - end - setup #rerun setup for setting the parameters - #####create the config file_end##### + # ####create the config file##### + $config[:revision] = 1 + File.open 'config.yml', 'w' do |f| # save contents of the config hash + f.write $config.to_yaml # ... in yaml + end + setup # rerun setup for setting the parameters + # ####create the config file_end##### end end -def tweet(artist, track) #function for creating the tweets out of a handed track - if "#{artist}#{track}".size < 263 then #123 because that's the number of chars left when including the hashtag etc - begin #it's just a check for the character limit - @tweetoutput = "♫ #{artist} - #{track} #NowPlaying" #this is the part of the function for tweets that fit the limit without chomping needed - @Twitter.update(@tweetoutput) #lets tweet it out - puts "[#{Time.new.strftime("%d-%m-%Y %H:%M:%S").to_s}] Tweet sent: #{@tweetoutput}" #console output and stuff - rescue => e - puts "rescued (probably twitter is down or some other shit): " + e.message #rescue when twitter is down when trying to tweet it (or some other shit) - sleep(3) #lets maybe wait a few seconds, if it's really down - retry while true #this rescue should be made more specific, otherwise some bad shit can happen +def tweet(artist, track) # function for creating the tweets out of a handed track + if "#{artist}#{track}".size < 263 # 123 because that's the number of chars left when including the hashtag etc + begin # it's just a check for the character limit + @tweetoutput = "♫ #{artist} - #{track} #NowPlaying" # this is the part of the function for tweets that fit the limit without chomping needed + @Twitter.update(@tweetoutput) # lets tweet it out + puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] Tweet sent: #{@tweetoutput}" # console output and stuff + rescue => e + puts 'rescued (probably twitter is down or some other shit): ' + e.message # rescue when twitter is down when trying to tweet it (or some other shit) + sleep(3) # lets maybe wait a few seconds, if it's really down + loop { retry } # this rescue should be made more specific, otherwise some bad shit can happen end else begin - artistlength = artist.size #counting the chars of the artist - chomper = 263 - artistlength - 3 #calculating how many chars we have left for the track name (minus 3 because "...") - @tweetoutput = "♫ #{artist} - #{track[0...chomper]}... #NowPlaying" #chomping the trackname and put together the tweet - @Twitter.update(@tweetoutput) #tweet that shit - puts "[#{Time.new.strftime("%d-%m-%Y %H:%M:%S").to_s}] Tweet sent: #{@tweetoutput}" - rescue => e - puts "rescued (probably twitter is down or some other shit): " + e.message + artistlength = artist.size # counting the chars of the artist + chomper = 263 - artistlength - 3 # calculating how many chars we have left for the track name (minus 3 because "...") + @tweetoutput = "♫ #{artist} - #{track[0...chomper]}... #NowPlaying" # chomping the trackname and put together the tweet + @Twitter.update(@tweetoutput) # tweet that shit + puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] Tweet sent: #{@tweetoutput}" + rescue => e + puts 'rescued (probably twitter is down or some other shit): ' + e.message sleep(3) - retry while true + loop { retry } end end end -def scrobbleread #function for getting the latest scrobbles from a profile - sleep(1) #wait a second, because api rate limits and stuff. 60 calls per minute is still plenty. - @recent = @lastfm.user.get_recent_tracks(user: @lastfmuser, limit: 1) #get latest scrobbles from lastfm's api - rescue => e #rescue when down - puts 'LastFM-API down: ' + e.message #in this case, this is good enough as it's just a GET. be more careful with POST. - retry while true +def scrobbleread # function for getting the latest scrobbles from a profile + sleep(1) # wait a second, because api rate limits and stuff. 60 calls per minute is still plenty. + @recent = @lastfm.user.get_recent_tracks(user: @lastfmuser, limit: 1) # get latest scrobbles from lastfm's api +rescue => e # rescue when down + puts 'LastFM-API down: ' + e.message # in this case, this is good enough as it's just a GET. be more careful with POST. + loop { retry } end -#####MAINLOOP##### #this is where all the functions before are called. it's already pretty organized here, but -begin #i'm sure, that i'll OOP the shit out of the rest some time in the future - setup #the setup! either create a config file, or init from a valid existing one - - @Twitter.update("[#{Time.new.strftime("%d-%m-%Y %H:%M:%S").to_s}] #{@version} by @dasinking == online") #welcome online - puts "[#{Time.new.strftime("%d-%m-%Y %H:%M:%S").to_s}] #{@version} by @dasinking == online" - - while 1 != 2 do #endless loop - begin #lastfm's api answer are weird. although we only call 1, we can get 2. why? because of active scrobbling. - scrobbleread #when you're still actively to a track, it also provides you with the last song you fully heard. - #tweet if no active scrobbling #this doesn't really make sense, as we only wanted one answer, BUT WE CAN ABUSE THIS, as it uses different types - if @recent.is_a? Hash #of answers for both of them. a hash for the single answer (no active scrobble) and an array for two (active) - $date1 = @recent["date"]["uts"] #getting the scrobble date of the latest answer in UTS (unix time stamp) - if $date1 != $date2 #comparing it to the last saved date. this results in a tweet with every start of tweetFM, but i'm fine with this - begin #if these differ from each other, we tweet the new song - tweet(@recent["artist"]["content"],@recent["name"]) #calling the tweet function and sending artist and track with it - $date2 = $date1 #setting the new date as the new pivot element - end - end - #tweet if active scrobbling #here's the if-cond for active scrobbling! - else if @recent.is_a? Array #yes, it's an array then. - $date1 = @recent[1]["date"]["uts"] #same shit as above, but we need to set an index for the array - if $date1 != $date2 #i use index 1, because i only want to tweet fully listened to songs - begin - tweet(@recent[1]["artist"]["content"],@recent[1]["name"]) #again, same stuff as above - $date2 = $date1 - end - else - #exception because of who the fuck knows - puts 'Unsupported API-Answer' #sometimes (surprisingly often) lastfm isn't down, but the api answers are rubbish. enjoy the spam in your CLI. +# ####MAINLOOP##### #this is where all the functions before are called. it's already pretty organized here, but +begin # i'm sure, that i'll OOP the shit out of the rest some time in the future + setup # the setup! either create a config file, or init from a valid existing one + + @Twitter.update("[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] #{@version} by @dasinking == online") # welcome online + puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] #{@version} by @dasinking == online" + + while 1 != 2 # endless loop + begin # lastfm's api answer are weird. although we only call 1, we can get 2. why? because of active scrobbling. + scrobbleread # when you're still actively to a track, it also provides you with the last song you fully heard. + # tweet if no active scrobbling #this doesn't really make sense, as we only wanted one answer, BUT WE CAN ABUSE THIS, as it uses different types + if @recent.is_a? Hash # of answers for both of them. a hash for the single answer (no active scrobble) and an array for two (active) + $date1 = @recent['date']['uts'] # getting the scrobble date of the latest answer in UTS (unix time stamp) + if $date1 != $date2 # comparing it to the last saved date. this results in a tweet with every start of tweetFM, but i'm fine with this + begin # if these differ from each other, we tweet the new song + tweet(@recent['artist']['content'], @recent['name']) # calling the tweet function and sending artist and track with it + $date2 = $date1 # setting the new date as the new pivot element end end + # tweet if active scrobbling #here's the if-cond for active scrobbling! + else if @recent.is_a? Array # yes, it's an array then. + $date1 = @recent[1]['date']['uts'] # same shit as above, but we need to set an index for the array + if $date1 != $date2 # i use index 1, because i only want to tweet fully listened to songs + begin + tweet(@recent[1]['artist']['content'], @recent[1]['name']) # again, same stuff as above + $date2 = $date1 + end + else + # exception because of who the fuck knows + puts 'Unsupported API-Answer' # sometimes (surprisingly often) lastfm isn't down, but the api answers are rubbish. enjoy the spam in your CLI. + end end end + end end - -end #a friend of mine once said, i should write more comments in my code. thank him for this clusterfuck of text everywhere: @_streamfire_ on twitter. +end # a friend of mine once said, i should write more comments in my code. thank him for this clusterfuck of text everywhere: @_streamfire_ on twitter. From 975ae40ccb307ee000ffb971bdc865f66a17ea9d Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Sun, 3 Dec 2017 19:44:54 +0100 Subject: [PATCH 2/5] Remove `yaml` gem from Gemfile, as it's part of Ruby's bundled gems --- Gemfile | 7 +++--- Gemfile.lock | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 Gemfile.lock diff --git a/Gemfile b/Gemfile index a8d3986..c8ae74a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,5 @@ -source "https://rubygems.org" +source 'https://rubygems.org' -gem 'yaml' -gem 'twitter', '~> 6.1.0' gem 'lastfm', '~> 1.27', '>=1.27.2' -gem 'oauth', '~> 0.5' \ No newline at end of file +gem 'oauth', '~> 0.5' +gem 'twitter', '~> 6.1.0' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..19f40df --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,71 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (5.1.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + buftok (0.2.0) + concurrent-ruby (1.0.5) + domain_name (0.5.20170404) + unf (>= 0.0.5, < 1.0.0) + equalizer (0.0.11) + faraday (0.11.0) + multipart-post (>= 1.2, < 3) + http (2.2.2) + addressable (~> 2.3) + http-cookie (~> 1.0) + http-form_data (~> 1.0.1) + http_parser.rb (~> 0.6.0) + http-cookie (1.0.3) + domain_name (~> 0.5) + http-form_data (1.0.3) + http_parser.rb (0.6.0) + httparty (0.15.6) + multi_xml (>= 0.5.2) + i18n (0.9.1) + concurrent-ruby (~> 1.0) + lastfm (1.27.2) + activesupport (>= 3.2.0) + httparty + xml-simple + memoizable (0.4.2) + thread_safe (~> 0.3, >= 0.3.1) + minitest (5.10.3) + multi_xml (0.6.0) + multipart-post (2.0.0) + naught (1.1.0) + oauth (0.5.3) + public_suffix (3.0.1) + simple_oauth (0.3.1) + thread_safe (0.3.6) + twitter (6.1.0) + addressable (~> 2.5) + buftok (~> 0.2.0) + equalizer (= 0.0.11) + faraday (~> 0.11.0) + http (~> 2.1) + http_parser.rb (~> 0.6.0) + memoizable (~> 0.4.2) + naught (~> 1.1) + simple_oauth (~> 0.3.1) + tzinfo (1.2.4) + thread_safe (~> 0.1) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.4) + xml-simple (1.1.5) + +PLATFORMS + ruby + +DEPENDENCIES + lastfm (~> 1.27, >= 1.27.2) + oauth (~> 0.5) + twitter (~> 6.1.0) + +BUNDLED WITH + 1.16.0 From 5acde9da53fa4e5f3f9ea99cf2d01d487cc0fe48 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Sun, 3 Dec 2017 19:45:12 +0100 Subject: [PATCH 3/5] Refactor everything! - Create new methods for specific stuff - Line-wrap most lines to 80 characters - Reduce some code duplication - Add new method for logging --- tweetFM.rb | 411 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 253 insertions(+), 158 deletions(-) mode change 100644 => 100755 tweetFM.rb diff --git a/tweetFM.rb b/tweetFM.rb old mode 100644 new mode 100755 index 1053b8d..6fb24b4 --- a/tweetFM.rb +++ b/tweetFM.rb @@ -1,3 +1,4 @@ + # dHdlZXRGTSB2NCBieSBkYXNpbmtpbmcgLSBtYWRlIGluIDIwMTYtMTcgd2l0aCA8Mw== @version = 'tweetFM_v4' @@ -6,189 +7,283 @@ require 'lastfm' require 'oauth' -OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE # only needed for some ruby installations on windows, when you get a certificate error (fuck that) +# only needed for some ruby installations on windows, when you get a +# certificate error (fuck that) +OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE -# ####twitter_auth##### +# ===== twitter_auth ===== +# wooooooah! api keys! +# those are public anyway, so it doesn't matter posting them publicly. :) @Twitter = Twitter::REST::Client.new do |config| - config.consumer_key = '4iTHA7VaA85qX0gaIT6fskn9f' # wooooooah! api keys! - config.consumer_secret = '3GQIVok9vUqob30DfQlghKLM7oACHqKaJtI1YMi90LfKI7a1KT' # those are public anyways, so it doesn't matter posting them publicly. :) + config.consumer_key = '4iTHA7VaA85qX0gaIT6fskn9f' + config.consumer_secret = '3GQIVok9vUqob30DfQlghKLM7oACHqKaJtI1YMi90LfKI7a1KT' end -# ####twitter_auth_end##### +# ===== twitter_auth_end ===== -# ####lastfm_auth##### -@lastfm = Lastfm.new('d40320e36eca2707150f55723630436e', 'aff6f8a58d4ad1a937e0128a83dec486') # especially those, because you can't create an app on last.fm for MONTHS now. you're welcome. -# ####lastfm_auth_end##### +# ===== lastfm_auth ===== +# especially those, because you can't create an app on last.fm for MONTHS now. +# you're welcome. +@lastfm = Lastfm.new( + 'd40320e36eca2707150f55723630436e', + 'aff6f8a58d4ad1a937e0128a83dec486' +) +# ===== lastfm_auth_end ===== -def setup - if File.file?('config.yml') == true # check for existing config - $config = { # opening the hash - - }.merge(YAML.load_file(File.expand_path('../config.yml', __FILE__))) # merging the existing config to check it's contents - - if $config[:revision] != 1 # search for revision. this procedure is futureproof by increasing the number! so smart!! - begin # older versions of tweetFM didn't have this config entry, so it will directly identify those configs - puts '' # those older versions use other keys and general entry names, so we want them gone. - puts "Welcome to #{@version}! Looks like your update was successful, but we're not done yet." - puts 'Your existing configuration is based on an older installation of tweetFM.' - puts 'A new configuration will be created, but before that, we need to delete the old one.' - puts 'If you have any emotional connection to it, create a backup now.' - puts "When you're done, or you don't care, press enter." - stub = $stdin.gets.strip # wait for enter press - File.delete('config.yml') # delete old config - $config = {} # zero the variable - setup # rerun setup for configuring the new config file - end # yo dawg, i heard you like configurations - else # config is found which is up-to-date. it's configurations will be set - begin - @Twitter.access_token = $config[:twitter_token] # adding twitter tokens from the valid config - @Twitter.access_token_secret = $config[:twitter_token_secret] - @lastfmuser = $config[:lastfm_user] # and the lastfm-username for parsing the latest scrobbles - if $config[:url] == true # resetting the url in the profile with every start of tweetFM, heheheh - @Twitter.update_profile(url: 'https://github.com/dasinking/tweetFM/') - end - end - end - else # o fuc, we need to setup - puts '' - puts 'Welcome, new user of tweetFM!' - puts "Before we can start spamming you and your friends' timeline, we need to configure some things." - puts "It won't take long!" +# This function initialises the $config hash with the values from config.yml +def init_existing + # load the existing config to check it's contents + $config = YAML.load_file(File.expand_path('../config.yml', __FILE__)) - $config = {} # opening the hash for incoming entries - # it's an hash, because we'll save those settings to an external file later. it's easier like that. - # ####twitter_auth##### + # search for revision. this procedure is futureproof by increasing the number! + # so smart!! + # older versions of tweetFM didn't have this config entry, so it will directly + # identify those configs + # those older versions use other keys and general entry names, so we want them + # gone. + if $config[:revision] != 1 puts '' - puts 'First we need access to Twitter.' - consumer = OAuth::Consumer.new(@Twitter.consumer_key, @Twitter.consumer_secret, site: 'https://api.twitter.com') # define where to send the request and it's parameters - request_token = consumer.get_request_token(oauth_callback: @callback_url) # requesting and saving first oauth answer + puts "Welcome to #{@version}! Looks like your update was successful, but we're not done yet." + puts 'Your existing configuration is based on an older installation of tweetFM.' + puts 'A new configuration will be created, but before that, we need to delete the old one.' + puts 'If you have any emotional connection to it, create a backup now.' + puts "When you're done, or you don't care, press enter." + $stdin.gets.strip # wait for enter press + File.delete('config.yml') # delete old config + $config = {} # zero the variable + return setup # rerun setup for configuring the new config file + end - url = request_token.authorize_url(oauth_callback: @callback_url) # saving the auth url separately + # config is found which is up-to-date. it's configurations will be set + # adding twitter tokens from the valid config + @Twitter.access_token = $config[:twitter_token] + @Twitter.access_token_secret = $config[:twitter_token_secret] + # and the lastfm-username for parsing the latest scrobbles + @lastfmuser = $config[:lastfm_user] + return unless $config[:url] + # resetting the url in the profile with every start of tweetFM, heheheh + @Twitter.update_profile(url: 'https://github.com/dasinking/tweetFM/') +end - puts "Open this URL in a browser: #{url}" - pin = '' # init pin variable (zeroing) - until pin =~ /^\d+$/ # loop for typing in the auth pin - print 'Enter PIN => ' - pin = $stdin.gets.strip # saving pin - end +# This function authenticates the user with twitter, sets the LastFM user name, +# creates a config and whatnot. +def init_new + puts '' + puts 'Welcome, new user of tweetFM!' + puts "Before we can start spamming you and your friends' timeline, we need to configure some things." + puts "It won't take long!" - @access_token = request_token.get_access_token(oauth_verifier: pin) # requesting the tokens with the auth pin and saving it + $config = {} # opening the hash for incoming entries + # it's an hash, because we'll save those settings to an external file later. + # it's easier this way. + init_new_twitter_auth + init_new_lastfm_username + init_new_sourcecode_link + init_new_create_config +end - $config[:twitter_token] = @access_token.token # defining the tokens in the config - $config[:twitter_token_secret] = @access_token.secret # like that, we need to reload setup in the end, so it defines the tokens +# This function initialises the user with Twitter. +def init_new_twitter_auth + # ===== twitter_auth ===== + puts '' + puts 'First we need access to Twitter.' - if @Twitter.user('dasinking').id == 78_006_580 # test whether or not i can access the api - puts '' - puts 'Successfully logged into Twitter!' # although it's basically impossible to get to this step without a valid auth - else - puts '' # but i already programmed it so yeah - puts 'somethings wrong with the auth process wtf' # all it does is requesting the user id of my profile and checking it - puts 'that should be impossible actually' # technically it's not even a good test, as the user id is requestable over public api - setup # so maybe i'll scrap this later on or improve it, we'll see - end - # ####twitter_auth_end##### + # define where to send the request and its parameters + consumer = OAuth::Consumer.new( + @Twitter.consumer_key, + @Twitter.consumer_secret, + site: 'https://api.twitter.com' + ) + # requesting and saving first oauth answer + request_token = consumer.get_request_token(oauth_callback: @callback_url) + + # saving the auth url separately + url = request_token.authorize_url(oauth_callback: @callback_url) - # ####lastfm username##### + puts "Open this URL in a browser: #{url}" + pin = '' # init pin variable (zeroing) + until pin =~ /^\d+$/ # loop for typing in the auth pin + print 'Enter PIN => ' + pin = $stdin.gets.strip # saving pin + end + + # requesting the tokens with the auth pin and saving it + @access_token = request_token.get_access_token(oauth_verifier: pin) + + # defining the tokens in the config + $config[:twitter_token] = @access_token.token + # like that, we need to reload setup in the end, so it defines the tokens + $config[:twitter_token_secret] = @access_token.secret + + # test whether or not i can access the api + if @Twitter.user('dasinking').id == 78_006_580 puts '' - puts 'Now, enter your last.fm-username:' - username = '' # init username variable (zeroing) - print 'Username => ' - username = $stdin.gets.strip # get input and save into var - $config[:lastfm_user] = username # saving username into config - # ####lastfm username_end##### - - # ####source code link y/n##### - puts - puts 'tweetFM is free and open source, so it would be really nice of you to link the GitHub repository in your profile.' - puts 'Do you want me to do this for you? (y/n)' - link = '' # init username variable (zeroing) - - print '' - link = $stdin.gets.strip # saving username - - if link == 'n' # when they type anything else than no it'll change the url #dickmove - $config[:url] = false - else - $config[:url] = true - end - # ####source code link y/n_end##### + puts 'Successfully logged into Twitter!' # although it's basically impossible to get to this step without a valid auth + return + end - # ####create the config file##### - $config[:revision] = 1 - File.open 'config.yml', 'w' do |f| # save contents of the config hash - f.write $config.to_yaml # ... in yaml - end - setup # rerun setup for setting the parameters - # ####create the config file_end##### + puts '' # but i already programmed it so yeah + puts 'somethings wrong with the auth process wtf' # all it does is requesting the user id of my profile and checking it + puts 'that should be impossible actually' # technically it's not even a good test, as the user id is requestable over public api + setup # so maybe i'll scrap this later on or improve it, we'll see + # ===== twitter_auth_end ===== +end + +# This function sets the LastFM username +def init_new_lastfm_username + # ===== lastfm username ===== + puts '' + puts 'Now, enter your last.fm-username:' + print 'Username => ' + username = $stdin.gets.strip # get input and save into var + $config[:lastfm_user] = username # saving username into config + # ===== lastfm username_end ===== +end + +# This function sets whether a link to the tweetFM repo should be set in the +# Twitter profile. +def init_new_sourcecode_link + # ===== source code link y/n ===== + puts + puts 'tweetFM is free and open source, so it would be really nice of you to link the GitHub repository in your profile.' + puts 'Do you want me to do this for you? (y/n)' + + print '' + link = $stdin.gets.strip # saving username + + # when they type anything else than no it'll change the url #dickmove + $config[:url] = if %w[n no nein nope nah].include?(link.downcase) + false + else + true + end + # ===== source code link y/n_end ===== +end + +# This function creates the config file. +def init_new_create_config + # ===== create the config file ===== + $config[:revision] = 1 + File.open('config.yml', 'w') do |f| # save contents of the config hash + f.write $config.to_yaml # ... in yaml end + setup # rerun setup for setting the parameters + # ===== create the config file_end ===== end -def tweet(artist, track) # function for creating the tweets out of a handed track - if "#{artist}#{track}".size < 263 # 123 because that's the number of chars left when including the hashtag etc - begin # it's just a check for the character limit - @tweetoutput = "♫ #{artist} - #{track} #NowPlaying" # this is the part of the function for tweets that fit the limit without chomping needed - @Twitter.update(@tweetoutput) # lets tweet it out - puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] Tweet sent: #{@tweetoutput}" # console output and stuff - rescue => e - puts 'rescued (probably twitter is down or some other shit): ' + e.message # rescue when twitter is down when trying to tweet it (or some other shit) - sleep(3) # lets maybe wait a few seconds, if it's really down - loop { retry } # this rescue should be made more specific, otherwise some bad shit can happen - end - else - begin - artistlength = artist.size # counting the chars of the artist - chomper = 263 - artistlength - 3 # calculating how many chars we have left for the track name (minus 3 because "...") - @tweetoutput = "♫ #{artist} - #{track[0...chomper]}... #NowPlaying" # chomping the trackname and put together the tweet - @Twitter.update(@tweetoutput) # tweet that shit - puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] Tweet sent: #{@tweetoutput}" - rescue => e - puts 'rescued (probably twitter is down or some other shit): ' + e.message - sleep(3) - loop { retry } - end +def setup + # check for existing config + return init_existing if File.file?('config.yml') + # o fuc, we need to setup + init_new +end + +# This function generates the tweet text. +def gen_tweet(artist, track, max_length: 263) + # max_length is 263 because that's the number of chars left when including + # the hashtag etc. + # calculating how many chars we have left for the track name if it is too + # long (minus 3 because "...") + chomper = max_length - artist.length - 3 + if "#{artist}#{track}".size < max_length + # no need to chomp anything, so return that! + return "♫ #{artist} - #{track} #NowPlaying" end + # return the chomped tweet + "♫ #{artist} - #{track[0...chomper]}... #NowPlaying" end -def scrobbleread # function for getting the latest scrobbles from a profile - sleep(1) # wait a second, because api rate limits and stuff. 60 calls per minute is still plenty. - @recent = @lastfm.user.get_recent_tracks(user: @lastfmuser, limit: 1) # get latest scrobbles from lastfm's api -rescue => e # rescue when down - puts 'LastFM-API down: ' + e.message # in this case, this is good enough as it's just a GET. be more careful with POST. +# function for creating the tweets out of a handed track +def tweet(artist, track) + @tweetoutput = gen_tweet(artist, track) + # lets tweet it out and print a status to the console + @Twitter.update(@tweetoutput) + log 'Tweet sent:', @tweetoutput.inspect +rescue StandardError => e + # rescue when twitter is down when trying to tweet it (or some other shit) + log 'rescued (probably twitter is down or some other shit):', e.message + # lets maybe wait a few seconds, if it's really down + sleep(3) + # this rescue should be made more specific, otherwise some bad shit can happen loop { retry } end -# ####MAINLOOP##### #this is where all the functions before are called. it's already pretty organized here, but -begin # i'm sure, that i'll OOP the shit out of the rest some time in the future - setup # the setup! either create a config file, or init from a valid existing one - - @Twitter.update("[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] #{@version} by @dasinking == online") # welcome online - puts "[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}] #{@version} by @dasinking == online" - - while 1 != 2 # endless loop - begin # lastfm's api answer are weird. although we only call 1, we can get 2. why? because of active scrobbling. - scrobbleread # when you're still actively to a track, it also provides you with the last song you fully heard. - # tweet if no active scrobbling #this doesn't really make sense, as we only wanted one answer, BUT WE CAN ABUSE THIS, as it uses different types - if @recent.is_a? Hash # of answers for both of them. a hash for the single answer (no active scrobble) and an array for two (active) - $date1 = @recent['date']['uts'] # getting the scrobble date of the latest answer in UTS (unix time stamp) - if $date1 != $date2 # comparing it to the last saved date. this results in a tweet with every start of tweetFM, but i'm fine with this - begin # if these differ from each other, we tweet the new song - tweet(@recent['artist']['content'], @recent['name']) # calling the tweet function and sending artist and track with it - $date2 = $date1 # setting the new date as the new pivot element - end +# function for getting the latest scrobbles from a profile +def scrobbleread + # wait a second, because api rate limits and stuff. 60 calls per minute is + # still plenty. + sleep(1) + # get latest scrobbles from lastfm's api + @recent = @lastfm.user.get_recent_tracks(user: @lastfmuser, limit: 1) +rescue StandardError => e # rescue when down + # in this case, this is good enough as it's just a GET. + # be more careful with POST. + log 'LastFM-API down: ' + e.message + loop { retry } +end + +# Builds a string for the log message including timestamp +def build_log(*msg) + ["[#{Time.new.strftime('%d-%m-%Y %H:%M:%S')}]", *msg].join(' ') +end + +# Prints out a message including the timestamp to the console +def log(*msg) + puts build_log(*msg) +end + +# function for tweeting out the latest track from a lastfm response +def tweet_latest_track(recent) + # getting the scrobble date of the latest answer in UTS (unix time stamp) + $date1 = recent.dig('date', 'uts') + # compare it to the last saved date. this results in a tweet with every start + # of tweetFM, but i'm fine with this + return if $date1 == $date2 + # if the dates differ from each other, we tweet the new song + # calling the tweet function and sending artist and track with it + tweet(recent.dig('artist', 'content'), recent['name']) + # and setting the new date + $date2 = $date1 +end + +# ===== MAINLOOP ===== +# this is where all the functions before are called. it's already pretty +# organised here, but i'm sure that i'll OOP the shit out of the rest some +# time in the future +begin + # the setup! either create a config file, or init from a valid existing one + setup + + # welcome online + onlinemsg = build_log(@version, 'by @dasinking == online') + @Twitter.update(onlinemsg) + puts onlinemsg + + # endless loop + loop do + scrobbleread + # lastfm's api answer are weird. although we only call 1, we can get 2. + # why? because of active scrobbling. + # when you're still actively listening to a track, it also provides you + # with the last song you fully heard. + # this doesn't really make sense, as we only wanted one answer, BUT WE + # CAN ABUSE THIS, as it uses different types of answers for both of them. + # a hash for the single answer (no active scrobble) and an array with the + # count of two (active scrobble) + if @recent.is_a?(Hash) + # tweet when no scrobble is active + tweet_latest_track(@recent) + elsif @recent.is_a?(Array) + # tweet when a scrobble is active + # I use index 1, because I only want to tweet fully listened to songs + tweet_latest_track(@recent[1]) + if $date1 == $date2 + # exception because of who the fuck knows + # sometimes (surprisingly often) lastfm isn't down, but the api + # answers are rubbish. enjoy the spam in your CLI. + log 'Unsupported API-Answer' end - # tweet if active scrobbling #here's the if-cond for active scrobbling! - else if @recent.is_a? Array # yes, it's an array then. - $date1 = @recent[1]['date']['uts'] # same shit as above, but we need to set an index for the array - if $date1 != $date2 # i use index 1, because i only want to tweet fully listened to songs - begin - tweet(@recent[1]['artist']['content'], @recent[1]['name']) # again, same stuff as above - $date2 = $date1 - end - else - # exception because of who the fuck knows - puts 'Unsupported API-Answer' # sometimes (surprisingly often) lastfm isn't down, but the api answers are rubbish. enjoy the spam in your CLI. - end end end - end end -end # a friend of mine once said, i should write more comments in my code. thank him for this clusterfuck of text everywhere: @_streamfire_ on twitter. +# a friend of mine once said, i should write more comments in my code. thank +# him for this clusterfuck of text everywhere: @_streamfire_ on twitter. From c734d77f4d90d00efe36c59b370dfe5028c82ba4 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Sun, 3 Dec 2017 19:47:24 +0100 Subject: [PATCH 4/5] Add shebang --- tweetFM.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tweetFM.rb b/tweetFM.rb index 6fb24b4..1c29aef 100755 --- a/tweetFM.rb +++ b/tweetFM.rb @@ -1,4 +1,4 @@ - +#!/usr/bin/env ruby # dHdlZXRGTSB2NCBieSBkYXNpbmtpbmcgLSBtYWRlIGluIDIwMTYtMTcgd2l0aCA8Mw== @version = 'tweetFM_v4' From 9380d2450fc59056628935d8b4fccb32603de597 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Sun, 3 Dec 2017 19:58:47 +0100 Subject: [PATCH 5/5] Fix retrying from rescue blocks, remove spammy message --- tweetFM.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tweetFM.rb b/tweetFM.rb index 1c29aef..861b06c 100755 --- a/tweetFM.rb +++ b/tweetFM.rb @@ -204,7 +204,7 @@ def tweet(artist, track) # lets maybe wait a few seconds, if it's really down sleep(3) # this rescue should be made more specific, otherwise some bad shit can happen - loop { retry } + retry end # function for getting the latest scrobbles from a profile @@ -218,7 +218,7 @@ def scrobbleread # in this case, this is good enough as it's just a GET. # be more careful with POST. log 'LastFM-API down: ' + e.message - loop { retry } + retry end # Builds a string for the log message including timestamp @@ -276,12 +276,12 @@ def tweet_latest_track(recent) # tweet when a scrobble is active # I use index 1, because I only want to tweet fully listened to songs tweet_latest_track(@recent[1]) - if $date1 == $date2 - # exception because of who the fuck knows - # sometimes (surprisingly often) lastfm isn't down, but the api - # answers are rubbish. enjoy the spam in your CLI. - log 'Unsupported API-Answer' - end + # if $date1 == $date2 + # # exception because of who the fuck knows + # # sometimes (surprisingly often) lastfm isn't down, but the api + # # answers are rubbish. enjoy the spam in your CLI. + # log 'Unsupported API-Answer' + # end end end end