From 1b05b87b04c0e3d6e8a4e7c891d1eea9aece298d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 21 Mar 2009 00:37:32 -0400 Subject: [PATCH] Added the beginnings of Megaporn support. There's still something missing, but the decryption routine is (probably) implemented correctly. --- src/websites/megaporn.rb | 173 ++++ test/fixtures/megaporn/E1LROW6E.html | 1326 ++++++++++++++++++++++++++ test/megaporn_test.rb | 86 ++ test/test_suite.rb | 1 + 4 files changed, 1586 insertions(+) create mode 100644 src/websites/megaporn.rb create mode 100644 test/fixtures/megaporn/E1LROW6E.html create mode 100644 test/megaporn_test.rb diff --git a/src/websites/megaporn.rb b/src/websites/megaporn.rb new file mode 100644 index 0000000..bbd55c2 --- /dev/null +++ b/src/websites/megaporn.rb @@ -0,0 +1,173 @@ +# +# Copyright Michael Orlitzky +# +# http://michael.orlitzky.com/ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# http://www.fsf.org/licensing/licenses/gpl.html +# + +# jcode still needed for String.each_char in Ruby 1.8.6. +require 'jcode' +require 'src/website' + +class Megaporn < Website + + VALID_MEGAPORN_URL_REGEX = /^(http:\/\/)?(www\.)?(megaporn|megavideo)\.com\/video\/\?v=[[:alnum:]]+$/ + + def self.owns_url?(url) + return url =~ VALID_MEGAPORN_URL_REGEX + end + + + def get_video_filename + # Just use the video id. + id_regex = /v=([[:alnum:]]+)/ + matches = id_regex.match(@url) + + if (matches.nil? || matches.length < 2) + return 'default.flv' + else + return (matches[1] + '.flv') + end + end + + + def get_video_url() + data = get_page_data(@url) + + # Megaporn attaches a numeric suffix to their 'www' + # hostname that (I suppose) is necessary to find the + # video file. The suffix is simply provided as a flash + # variable, though. + host_suffix = parse_flash_variable(data, 's') + + # There are also two or three keys, sent as Flash variables, + # that are used in the "decryption" routine. We get integers + # to be on the safe side. + key1 = parse_flash_variable(data, 'k1').to_i + key2 = parse_flash_variable(data, 'k2').to_i + + # This is a magic hex string, passed to the decryption + # routine along with key1 and key2. + seed = parse_flash_variable(data, 'un') + + secret_path = self.decrypt(seed, key1, key2) + + # Note that the path to the video file looks like a folder. + # We need to remember to save it as a file. + return "http://www#{host_suffix}.#{self.domain}/videos/#{secret_path}/" + end + + + protected + + def domain + # I'm guessing they serve videos from both of these domains. + if (@url.include?('megavideo.com')) + return 'megavideo.com' + else + return 'megaporn.com' + end + end + + + def parse_flash_variable(data, variable_name) + # The Flash variables differ only in name, so this method can + # parse them all. + var_regex = /flashvars\.#{variable_name} = \"(.+?)\"/ + matches = var_regex.match(data) + + if (matches.nil? || matches.length < 2) + raise StandardError.new("Could not parse Flash variable: #{variable_name}.") + end + + return matches[1] + end + + + def string_to_binary_array(target_string) + binary_array = [] + + target_string.each_char do |c| + binary_int = c.to_i(16).to_s(2).to_i + binary_char = sprintf('%04d', binary_int) + binary_char.each_char do |bc| + binary_array << bc + end + end + + return binary_array + end + + + def binary_words_to_hex(target_array) + hex = '' + + target_array.each do |word| + hex << word.to_i(2).to_s(16) + end + + return hex + end + + + def decrypt(seed, key1, key2) + # I reverse-engineered this one myself. Suck it, megaporn. + # + # Round 1. Convert the seed to its binary reprentation, + # storing each bit as an element of an array. + loc1 = string_to_binary_array(seed) + + # Round 2 + loc6 = [] + key1 = key1.to_i + key2 = key2.to_i + 0.upto(383) do |loc3| + key1 = (key1 * 11 + 77213) % 81371 + key2 = (key2 * 17 + 92717) % 192811 + loc6[loc3] = (key1 + key2) % 128 + end + + + # Round 3 + 256.downto(0) do |loc3| + loc5 = loc6[loc3] + loc4 = loc3 % 128 + loc8 = loc1[loc5] + loc1[loc5] = loc1[loc4] + loc1[loc4] = loc8 + end + + + # Round 4 + 0.upto(127) do |loc3| + loc1[loc3] = (loc1[loc3].to_i ^ loc6[loc3 + 256]) & 1 + end + + + # Round 5 + loc12 = loc1.to_s + offset = 0 + loc7 = [] + while (offset < loc12.length) + loc7 << loc12[offset, 4]; + offset += 4 + end + + + # Round 6 + return binary_words_to_hex(loc7) + end + + +end diff --git a/test/fixtures/megaporn/E1LROW6E.html b/test/fixtures/megaporn/E1LROW6E.html new file mode 100644 index 0000000..0b2a2df --- /dev/null +++ b/test/fixtures/megaporn/E1LROW6E.html @@ -0,0 +1,1326 @@ + + + + + + + + +Megaporn Video + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+ + + + + + + + + + + +
+ +
+
+ + + + +
+
+
+ +
+ + +
+ +
+ + + + +
+ + + + +
+ + + +
language
+
+
+ + + + +
Login    |    Register
+ + + + +
+ + + + + + + +
+
+ + + + + +
+ + + + + + + + + + + + + + +
+
+
+
+ + + + +
+ Please upgrade to the latest version of the Adobe Flash player.


+


+ + +
+
+
+
+ + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/megaporn_test.rb b/test/megaporn_test.rb new file mode 100644 index 0000000..f033d5b --- /dev/null +++ b/test/megaporn_test.rb @@ -0,0 +1,86 @@ +# +# Copyright Michael Orlitzky +# +# http://michael.orlitzky.com/ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# http://www.fsf.org/licensing/licenses/gpl.html +# + +require 'test/unit' +require 'src/websites/megaporn' + + +class MegapornTest < Test::Unit::TestCase + + def test_owns_megaporn_urls + assert(Megaporn.owns_url?('http://www.megaporn.com/video/?v=E1LROW6E')) + end + + + def test_doesnt_own_infoq_urls + assert(!Megaporn.owns_url?('http://www.infoq.com/interviews/jim-weirich-discusses-rake')) + end + + + def test_doesnt_own_redtube_urls + assert(!Megaporn.owns_url?('http://www.redtube.com/6807')) + assert(!Megaporn.owns_url?('www.redtube.com/6807')) + assert(!Megaporn.owns_url?('http://redtube.com/6807')) + assert(!Megaporn.owns_url?('redtube.com/6807')) + end + + + def test_doesnt_own_efukt_urls + assert(!Megaporn.owns_url?('http://www.efukt.com/2308_How_To_Fuck_Like_A_King.html')) + assert(!Megaporn.owns_url?('http://www.efukt.com/2304_The_Dumbest_Porno_Ever_Made.html')) + end + + + def test_decryption + mp = Megaporn.new(nil) + expected_result = '3de0ae51c90c7b100cc41e899648ac3c' + actual_result = mp.send('decrypt', 'becc1abe04b5ab8cb10dc7d29a497958', '49298', '63031') + assert_equal(expected_result, actual_result) + end + + + def test_parse_flash_variable + mp = Megaporn.new(nil) + page_data = nil + + File.open('test/fixtures/megaporn/E1LROW6E.html') do |f| + page_data = f.read + end + + # Seed + expected_result = '71eef99c126511b92b770d654ecd25c8' + actual_result = mp.send('parse_flash_variable', page_data, 'un') + assert_equal(expected_result, actual_result) + + # key1 + expected_result = '63233' + actual_result = mp.send('parse_flash_variable', page_data, 'k1') + assert_equal(expected_result, actual_result) + + # key2 + expected_result = '185149' + actual_result = mp.send('parse_flash_variable', page_data, 'k2') + assert_equal(expected_result, actual_result) + + # Host suffix + expected_result = '118' + actual_result = mp.send('parse_flash_variable', page_data, 's') + assert_equal(expected_result, actual_result) + end + +end diff --git a/test/test_suite.rb b/test/test_suite.rb index a1a4390..9312ab8 100644 --- a/test/test_suite.rb +++ b/test/test_suite.rb @@ -20,6 +20,7 @@ require 'test/efukt_test' require 'test/fuckedtube_test' require 'test/howcast_test' require 'test/infoq_test' +require 'test/megaporn_test' require 'test/redtube_test' require 'test/veoh_test' require 'test/uri_utilities_test' -- 2.44.2