teecket 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2188b057b1c90ca438cd0a9c8d1800fdddd05c2f
4
+ data.tar.gz: 385db9dad3eccd44072b238b35404303595e64e3
5
+ SHA512:
6
+ metadata.gz: 83801f55ee2aa27350e4da061cffd2398681c56e4f473865c50f83ea903fcb9342e623506c49e8d6394c6941f759ac4ec162e76a0293145e8a66cdb8057092dc
7
+ data.tar.gz: 03c6c00aa42395bd1cd9f99261675094f3cf5f9e50b9b298c11563c244ae4ecb03259705f228a8f052b06a9d0556bdfbf19382395a13a960a2342fecccc2e381
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'teecket'
4
+
5
+ if ARGV.count == 3
6
+ Teecket.search({ from: ARGV[0], to: ARGV[1], date: ARGV[2]})
7
+ else
8
+ puts 'Example: teecket KBR KUL 30-07-2015'
9
+ end
10
+
@@ -0,0 +1,28 @@
1
+ require 'teecket/flight'
2
+ require 'teecket/air_asia'
3
+ require 'teecket/malaysia_airlines'
4
+ require 'teecket/malindo_air'
5
+ require 'teecket/printer'
6
+ require 'teecket/firefly'
7
+
8
+ require 'byebug'
9
+
10
+ class Teecket
11
+ def self.search(params)
12
+ airasia = AirAsia.new({ from: params[:from], to: params[:to], date: params[:date] })
13
+ airasia.get
14
+
15
+ firefly = Firefly.new({ from: params[:from], to: params[:to], date: params[:date] })
16
+ firefly.get
17
+
18
+ mas = MalaysiaAirlines.new({ from: params[:from], to: params[:to], date: params[:date] })
19
+ mas.get
20
+
21
+ malindo = MalindoAir.new({ from: params[:from], to: params[:to], date: params[:date] })
22
+ malindo.get
23
+
24
+ output = airasia.fares + mas.fares + malindo.fares + firefly.fares
25
+
26
+ puts Printer.table(output)
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ class AirAsia < Flight
2
+ def get
3
+ uri = URI('https://argon.airasia.com/api/7.0/search')
4
+
5
+ http = Net::HTTP.new(uri.host, uri.port)
6
+ http.use_ssl = true
7
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
8
+
9
+ req = Net::HTTP::Post.new(uri.path)
10
+ req.body = "type=classic&origin=#{from}&destination=#{to}&depart=#{date}&return=&passenger-count=1&child-count=0&infant-count=0&currency=MYR&days=1"
11
+
12
+ res = http.request(req)
13
+
14
+ result = JSON.parse(res.body)
15
+
16
+ if result['session-id']
17
+ begin
18
+ result['depart'][date]['details']['low-fare'].each do |rs|
19
+ depart_at = DateTime.parse(rs['segments'][0]['departure-datetime'])
20
+ arrive_at = DateTime.parse(rs['segments'][0]['arrival-datetime'])
21
+ fare = rs['total']['adult']
22
+ flight_number = rs['segments'][0]['flight-number']
23
+ origin = rs['segments'][0]['origincode']
24
+ destination = rs['segments'][0]['destinationcode']
25
+
26
+ depart_at = depart_at.strftime('%I:%M %p')
27
+ arrive_at = arrive_at.strftime('%I:%M %p')
28
+ fare = sprintf("%.2f", fare)
29
+ flight_number = flight_number.gsub(/ /, '')
30
+
31
+ fares << { flight_name: 'AirAsia',
32
+ flight_number: flight_number,
33
+ origin: origin,
34
+ destination: destination,
35
+ depart_at: depart_at,
36
+ arrive_at: arrive_at,
37
+ fare: fare }
38
+ end
39
+ rescue StandardError
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ require 'nokogiri'
2
+
3
+ class Firefly < Flight
4
+ def get
5
+
6
+ uri = URI('https://m.fireflyz.com.my/')
7
+
8
+ http = Net::HTTP.new(uri.host, uri.port)
9
+ http.use_ssl = true
10
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
11
+
12
+ req = Net::HTTP::Get.new(uri.path)
13
+
14
+ res = http.request(req)
15
+
16
+ cookie = res['Set-Cookie']
17
+
18
+ uri = URI('https://m.fireflyz.com.my/Search')
19
+
20
+ http = Net::HTTP.new(uri.host, uri.port)
21
+ http.use_ssl = true
22
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
23
+
24
+ req = Net::HTTP::Get.new(uri.path, initheader = { 'Cookie' => cookie})
25
+
26
+ cookie = res['Set-Cookie']
27
+
28
+ uri = URI('https://m.fireflyz.com.my/Search')
29
+
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = true
32
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
+
34
+ req = Net::HTTP::Post.new(uri.path, initheader = { 'Cookie' => cookie})
35
+ req.body = 'type=2&departure_station=KBR&arrival_station=SZB&departure_date=30%2F06%2F2015&return_date=30%2F06%2F2015&adult=1&infant=0'
36
+
37
+ res = http.request(req)
38
+
39
+ if res['location']
40
+ uri = URI(res['location'])
41
+
42
+ http = Net::HTTP.new(uri.host, uri.port)
43
+ http.use_ssl = true
44
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
45
+
46
+ req = Net::HTTP::Get.new(uri.path, initheader = { 'Cookie' => cookie})
47
+
48
+ res = http.request(req)
49
+
50
+ doc = Nokogiri::HTML(res.body)
51
+
52
+ doc.css('div.market1').each_with_index do |elem, i|
53
+ depart_at = doc.css('div.market1')[i].css('div.visible-xs').css('table')[1].css('td')[0].text.strip
54
+ arrive_at = doc.css('div.market1')[i].css('div.visible-xs').css('table')[1].css('td')[1].text.strip
55
+ fare = doc.css('div.market1')[i].css('div.visible-xs > div').text.strip
56
+ flight_number = doc.css('div.market1')[i].css('div.visible-xs').css('table')[0].text.strip
57
+ origin = doc.css('div.market1')[i]['onclick'].scan(/~[A-Z]{3}~/)[0].gsub('~', '')
58
+ destination = doc.css('div.market1')[i]['onclick'].scan(/~[A-Z]{3}~/)[1].gsub('~', '')
59
+
60
+ depart_at = DateTime.parse("#{date} #{depart_at.gsub(/\t/, '').match(/^(.*?)(AM|PM)/).to_s}").strftime('%I:%M %p')
61
+ arrive_at = DateTime.parse("#{date} #{arrive_at.gsub(/\t/, '').match(/^(.*?)(AM|PM)/).to_s}").strftime('%I:%M %p')
62
+ fare = fare.gsub(/ MYR/, '')
63
+ flight_number = flight_number.gsub(/ /, '').gsub(/FLIGHTNO\./, '')
64
+
65
+ fares << { flight_name: 'Firefly',
66
+ flight_number: flight_number,
67
+ origin: origin,
68
+ destination: destination,
69
+ depart_at: depart_at,
70
+ arrive_at: arrive_at,
71
+ fare: fare }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,15 @@
1
+ require 'net/http'
2
+ require 'openssl'
3
+ require 'json'
4
+
5
+ class Flight
6
+ attr_reader :from, :to, :date, :fares
7
+
8
+ def initialize(params)
9
+ @from = params[:from]
10
+ @to = params[:to]
11
+ @date = params[:date]
12
+
13
+ @fares = []
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ class MalaysiaAirlines < Flight
2
+ def get
3
+ new_date = DateTime.parse(date)
4
+ new_date = new_date.strftime('%Y-%m-%d')
5
+
6
+ uri = URI("https://flymh.mobi/TravelAPI/travelapi/shop/1/mh/#{from}/#{to}/1/0/0/Economy/#{new_date}/")
7
+
8
+ http = Net::HTTP.new(uri.host, uri.port)
9
+ http.use_ssl = true
10
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
11
+
12
+ req = Net::HTTP::Get.new(uri.path, initHeader = { 'X-apiKey' => '52e6d6d613d3a3e825ac02253fe6b5a4'})
13
+
14
+ res = http.request(req)
15
+ res.body.gsub!(/^fn\(/, '')
16
+ res.body.gsub!(/\)/, '')
17
+
18
+ result = JSON.parse(res.body)
19
+
20
+ if result['success']
21
+ result['outboundOptions'].each do |rs|
22
+ depart_at = DateTime.parse(rs['flights'][0]['depScheduled'])
23
+ arrive_at = DateTime.parse(rs['flights'][0]['arrScheduled'])
24
+ fare = rs['fareDetails']['totalTripFare']
25
+ flight_number = rs['flights'][0]['marketingAirline'] + rs['flights'][0]['flightNumber']
26
+ origin = rs['flights'][0]['departureAirport']['code']
27
+ destination = rs['flights'][0]['arrivalAirport']['code']
28
+
29
+ depart_at = depart_at.strftime('%I:%M %p')
30
+ arrive_at = arrive_at.strftime('%I:%M %p')
31
+ fare = sprintf("%.2f", fare)
32
+
33
+ fares << { flight_name: 'Malaysia Airlines',
34
+ flight_number: flight_number,
35
+ origin: origin,
36
+ destination: destination,
37
+ depart_at: depart_at,
38
+ arrive_at: arrive_at,
39
+ fare: fare }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,60 @@
1
+ class MalindoAir < Flight
2
+ def get
3
+ new_date = DateTime.parse(date)
4
+ new_date = new_date.strftime('%Q')
5
+
6
+ uri = URI('https://mobileapi.malindoair.com/GQWCF_FlightEngine/GQDPMobileBookingService.svc/InitializeGQService')
7
+
8
+ http = Net::HTTP.new(uri.host, uri.port)
9
+ http.use_ssl = true
10
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
11
+
12
+ req = Net::HTTP::Post.new(uri.path, initheader = { 'Content-Type' => 'application/json' })
13
+ req.body = '{"B2BID":"0","UserLoginId":"0","CustomerUserID":91,"Language":"en-GB","isearchType":"15"}'
14
+
15
+ res = http.request(req)
16
+ key = res['wscContext']
17
+
18
+ if key
19
+ uri = URI('https://mobileapi.malindoair.com/GQWCF_FlightEngine/GQDPMobileBookingService.svc/SearchAirlineFlights')
20
+
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.use_ssl = true
23
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
24
+
25
+ req = Net::HTTP::Post.new(uri.path, initheader = { 'Content-Type' => 'application/json',
26
+ 'WscContext' => key })
27
+
28
+ payload = "{\"sd\":{\"Adults\":1,\"AirlineCode\":\"\",\"ArrivalCity\":\"#{to}\",\"ArrivalCityName\":null,\"BookingClass\":null,\"CabinClass\":0,\"ChildAge\":[],\"Children\":0,\"CustomerId\":0,\"CustomerType\":0,\"CustomerUserId\":91,\"DepartureCity\":\"#{from}\",\"DepartureCityName\":null,\"DepartureDate\":\"/Date(#{new_date})/\",\"DepartureDateGap\":0,\"DirectFlightsOnly\":false,\"Infants\":0,\"IsPackageUpsell\":false,\"JourneyType\":1,\"ReturnDate\":\"/Date(-2208988800000)/\",\"ReturnDateGap\":0,\"SearchOption\":1},\"fsc\":\"0\"}"
29
+
30
+ req.body = payload
31
+
32
+ res = http.request(req)
33
+
34
+ result = JSON.parse(res.body)
35
+
36
+ if result['SearchAirlineFlightsResult']
37
+ result['SearchAirlineFlightsResult'].each do |rs|
38
+ depart_at = rs['DepartureDate']
39
+ arrive_at = rs['ArrivalDate']
40
+ fare = rs['FlightAmount']
41
+ flight_number = rs['MACode'] + rs['FlightNo']
42
+ origin = rs['DepCity']
43
+ destination = rs['ArrCity']
44
+
45
+ depart_at = DateTime.strptime(depart_at.gsub(/^\/Date\(|\)\//, ''), '%Q').strftime('%I:%M %p')
46
+ arrive_at = DateTime.strptime(arrive_at.gsub(/^\/Date\(|\)\//, ''), '%Q').strftime('%I:%M %p')
47
+ fare = sprintf("%.2f", fare)
48
+
49
+ fares << { flight_name: 'Malindo Air',
50
+ flight_number: flight_number,
51
+ origin: origin,
52
+ destination: destination,
53
+ depart_at: depart_at,
54
+ arrive_at: arrive_at,
55
+ fare: fare }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ require 'terminal-table'
2
+
3
+ class Printer
4
+ def self.table(rows = [])
5
+ headings = ['Flight', 'Flight #', 'Origin', 'Destination', 'Depart', 'Arrive', 'Fare (RM)']
6
+
7
+ new_rows = rows.map { |row| row.values }
8
+
9
+ Terminal::Table.new(headings: headings, rows: new_rows)
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: teecket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Amree Zaid
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminal-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.4.5
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.4'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.4.5
33
+ - !ruby/object:Gem::Dependency
34
+ name: nokogiri
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.6'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.6.6.2
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.6'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.6.6.2
53
+ - !ruby/object:Gem::Dependency
54
+ name: byebug
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.0'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 5.0.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '5.0'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 5.0.0
73
+ description: Search ticket's fare for all major airlines in Malaysia at once
74
+ email: mohd.amree@gmail.com
75
+ executables:
76
+ - teecket
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - bin/teecket
81
+ - lib/teecket.rb
82
+ - lib/teecket/air_asia.rb
83
+ - lib/teecket/firefly.rb
84
+ - lib/teecket/flight.rb
85
+ - lib/teecket/malaysia_airlines.rb
86
+ - lib/teecket/malindo_air.rb
87
+ - lib/teecket/printer.rb
88
+ homepage: https://github.com/amree/teecket
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Search for flights fare in Malaysia
112
+ test_files: []