2 # Copyright Michael Orlitzky
4 # http://michael.orlitzky.com/
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # http://www.fsf.org/licensing/licenses/gpl.html
19 # jcode still needed for String.each_char in Ruby 1.8.6.
23 class Megaporn
< Website
25 VALID_MEGAPORN_URL_REGEX
= /^(http:\/\
/)?(www\.)?(megaporn|megavideo)\.com\/video\
/\?v=[[:alnum:]]+$/
27 def self.owns_url
?(url
)
28 return url
=~ VALID_MEGAPORN_URL_REGEX
32 def get_video_filename
33 # Just use the video id.
34 id_regex
= /v=([[:alnum:]]+)/
35 matches
= id_regex
.match(@url)
37 if (matches
.nil? || matches
.length
< 2)
40 return (matches
[1] +
'.flv')
46 data = get_page_data(@url)
48 # Megaporn attaches a numeric suffix to their 'www'
49 # hostname that (I suppose) is necessary to find the
50 # video file. The suffix is simply provided as a flash
52 host_suffix
= parse_flash_variable(data, 's')
54 # There are also two or three keys, sent as Flash variables,
55 # that are used in the "decryption" routine. We get integers
56 # to be on the safe side.
57 key1
= parse_flash_variable(data, 'k1').to_i
58 key2
= parse_flash_variable(data, 'k2').to_i
60 # This is a magic hex string, passed to the decryption
61 # routine along with key1 and key2.
62 seed
= parse_flash_variable(data, 'un')
64 secret_path
= self.decrypt(seed
, key1
, key2
)
66 # Note that the path to the video file looks like a folder.
67 # We need to remember to save it as a file.
68 return "http://www#{host_suffix}.#{self.domain}/videos/#{secret_path}/"
75 # I'm guessing they serve videos from both of these domains.
76 if (@url.include?('megavideo.com'))
77 return 'megavideo.com'
84 def parse_flash_variable(data, variable_name
)
85 # The Flash variables differ only in name, so this method can
87 var_regex
= /flashvars\.#{variable_name} = \"(.+?)\"/
88 matches
= var_regex
.match(data)
90 if (matches
.nil? || matches
.length
< 2)
91 raise StandardError
.new("Could not parse Flash variable: #{variable_name}.")
98 def string_to_binary_array(target_string
)
101 target_string
.each_char
do |c
|
102 binary_int
= c
.to_i(16).to_s(2).to_i
103 binary_char
= sprintf('%04d', binary_int
)
104 binary_char
.each_char
do |bc
|
113 def binary_words_to_hex(target_array
)
116 target_array
.each
do |word
|
117 hex
<< word
.to_i(2).to_s(16)
124 def decrypt(seed
, key1
, key2
)
125 # I reverse-engineered this one myself. Suck it, megaporn.
127 # Round 1. Convert the seed to its binary reprentation,
128 # storing each bit as an element of an array.
129 loc1
= string_to_binary_array(seed
)
135 0.upto(383) do |loc3
|
136 key1
= (key1
* 11 +
77213) % 81371
137 key2
= (key2
* 17 +
92717) % 192811
138 loc6
[loc3
] = (key1 + key2
) % 128
143 256.downto(0) do |loc3
|
147 loc1
[loc5
] = loc1
[loc4
]
153 0.upto(127) do |loc3
|
154 loc1
[loc3
] = (loc1
[loc3
].to_i ^ loc6
[loc3 +
256]) & 1
162 while (offset
< loc12
.length
)
163 loc7
<< loc12
[offset
, 4];
169 return binary_words_to_hex(loc7
)