Skip to content

Commit

Permalink
Delete Facebook code. Discuss here: #5.
Browse files Browse the repository at this point in the history
  • Loading branch information
stefansundin committed Aug 28, 2020
1 parent 3faa634 commit 5a0b18a
Show file tree
Hide file tree
Showing 11 changed files with 3 additions and 299 deletions.
3 changes: 0 additions & 3 deletions .dockerenv.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ REDIS_URL=redis://redis:6379

#VIMEO_ACCESS_TOKEN=

#FACEBOOK_APP_ID=
#FACEBOOK_APP_SECRET=

#SOUNDCLOUD_CLIENT_ID=

#TWITCH_CLIENT_ID=
Expand Down
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ REDIS_URL=redis://localhost:6379/3

#VIMEO_ACCESS_TOKEN=

#FACEBOOK_APP_ID=
#FACEBOOK_APP_SECRET=

#SOUNDCLOUD_CLIENT_ID=

#TWITCH_CLIENT_ID=
Expand Down
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,7 @@ Go to the [Vimeo developer website](https://developer.vimeo.com/apps) and create

#### Facebook

**Note:** This requires an app with the [Page Public Content Access](https://developers.facebook.com/docs/apps/review/feature#reference-PAGES_ACCESS) permission which requires manual approval from Facebook and is quite difficult to get. The official RSSBox website doesn't support Facebook anymore for this reason.

Go to the [Facebook developer website](https://developers.facebook.com/) and create an app. Copy your app id and secret.

Facebook live hax: After a live stream has ended, trying to access the stream via playlist.m3u8 will still give you a list of .ts files, however the domain is `interncache-prn.fbcdn.net` which doesn't resolve. However, if you edit your `/etc/hosts` file and point that domain to the IP of `origincache-prn.fbcdn.net`, you can watch the video again (use `dig origincache-prn.fbcdn.net +short`). This only works for a couple of days after the live event.
Facebook was supported in the past, but I have been unable to obtain API access since they locked it down in 2018. Maybe we can rebuild it some day, but using scraping techniques or something. [Discuss here.](https://github.com/stefansundin/rssbox/issues/5)

#### SoundCloud

Expand Down
2 changes: 0 additions & 2 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ REDIS_URL=redis://localhost:6379/3
#TWITTER_ACCESS_TOKEN=
#GOOGLE_API_KEY=
#VIMEO_ACCESS_TOKEN=
#FACEBOOK_APP_ID=
#FACEBOOK_APP_SECRET=
#SOUNDCLOUD_CLIENT_ID=
#TWITCH_CLIENT_ID=
#TWITCHTOKEN_CLIENT_ID=
Expand Down
8 changes: 0 additions & 8 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@
"description": "Your Vimeo access token.",
"required": false
},
"FACEBOOK_APP_ID": {
"description": "Your Facebook app id.",
"required": false
},
"FACEBOOK_APP_SECRET": {
"description": "Your Facebook app secret.",
"required": false
},
"SOUNDCLOUD_CLIENT_ID": {
"description": "Your SoundCloud client id.",
"required": false
Expand Down
149 changes: 1 addition & 148 deletions app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@
redirect Addressable::URI.new(path: "/twitter", query_values: params).normalize.to_s
elsif /^https?:\/\/(?:www\.|gaming\.)?youtu(?:\.be|be\.com)/ =~ params[:q]
redirect Addressable::URI.new(path: "/youtube", query_values: params).normalize.to_s
elsif /^https?:\/\/(?:www\.)?facebook\.com/ =~ params[:q]
redirect Addressable::URI.new(path: "/facebook", query_values: params).normalize.to_s
elsif /^https?:\/\/(?:www\.)?instagram\.com/ =~ params[:q]
redirect Addressable::URI.new(path: "/instagram", query_values: params).normalize.to_s
elsif /^https?:\/\/(?:www\.)?(?:periscope|pscp)\.tv/ =~ params[:q]
Expand Down Expand Up @@ -402,153 +400,8 @@
end
end

get "/facebook" do
return [404, "Credentials not configured"] if !ENV["FACEBOOK_APP_ID"] || !ENV["FACEBOOK_APP_SECRET"]
return [400, "Insufficient parameters"] if params[:q].empty?

params[:q].gsub!("facebookcorewwwi.onion", "facebook.com") if params[:q].include?("facebookcorewwwi.onion")

if /https:\/\/www\.facebook\.com\/plugins\/.+[?&]href=(?<href>.+)$/ =~ params[:q]
# https://www.facebook.com/plugins/video.php?href=https%3A%2F%2Fwww.facebook.com%2Finfectedmushroom%2Fvideos%2F10154638763917261%2F&show_text=0&width=400
params[:q] = CGI.unescape(href)
end

if /facebook\.com\/pages\/[^\/]+\/(?<id>\d+)/ =~ params[:q]
# https://www.facebook.com/pages/Lule%C3%A5-Sweden/106412259396611?fref=ts
elsif /facebook\.com\/groups\/(?<id>\d+)/ =~ params[:q]
# https://www.facebook.com/groups/223764997793315
elsif /facebook\.com\/video\/[^\d]+(?<id>\d+)/ =~ params[:q]
# https://www.facebook.com/video/embed?video_id=1192228974143110
elsif /facebook\.com\/[^\/]+-(?<id>[\d]+)/ =~ params[:q]
# https://www.facebook.com/TNG-Recuts-867357396651373/
elsif /facebook\.com\/(?:pg\/)?(?<id>[^\/?#]+)/ =~ params[:q]
# https://www.facebook.com/celldweller/info?tab=overview
else
id = params[:q]
end

response = Facebook.get("/", query: { id: id, metadata: "1" })
return [response.code, "Can't find a page with that name. Sorry."] if response.code == 404
return [response.code, "#{Facebook::BASE_URL}/#{id} returned code #{response.code}."] if response.code == 400
raise(FacebookError, response) if !response.success?
data = response.json
if data["metadata"]["fields"].any? { |field| field["name"] == "from" }
# this is needed if the url is for e.g. a photo and not the main page
response = Facebook.get("/", query: { id: id, fields: "from", metadata: "1" })
raise(FacebookError, response) if !response.success?
id = response.json["from"]["id"]
response = Facebook.get("/", query: { id: id, metadata: "1" })
raise(FacebookError, response) if !response.success?
data = response.json
end
if data["metadata"]["fields"].any? { |field| field["name"] == "username" }
response = Facebook.get("/", query: { id: id, fields: "username,name" })
raise(FacebookError, response) if !response.success?
data = response.json
end

return [404, "Please use a link directly to the Facebook page."] if !data["id"].numeric?
redirect Addressable::URI.new(path: "/facebook/#{data["id"]}/#{data["username"] || data["name"]}", query_values: params.slice(:type)).normalize.to_s
end

get "/facebook/download" do
return [404, "Credentials not configured"] if !ENV["FACEBOOK_APP_ID"] || !ENV["FACEBOOK_APP_SECRET"]

if /\/(?<id>\d+)/ =~ params[:url]
# https://www.facebook.com/infectedmushroom/videos/10153430677732261/
# https://www.facebook.com/infectedmushroom/videos/vb.8811047260/10153371214897261/?type=2&theater
elsif /\d+_(?<id>\d+)/ =~ params[:url]
elsif /v=(?<id>\d+)/ =~ params[:url]
elsif /(?<id>\d+)/ =~ params[:url]
else
id = params[:url]
end

response = HTTP.get("https://www.facebook.com/#{id}")
response = HTTP.get(response.redirect_url) if response.redirect_same_origin?
if response.success?
if /hd_src(?:_no_ratelimit)?:"(?<url>[^"]+)"/ =~ response.body
elsif /https:\/\/[^"]+_#{id}_[^"]+\.jpg[^"]+/o =~ response.body
# This is not the best quality of the picture, but it will have to do
url = CGI.unescapeHTML($&)
end
if !url
return [404, "Video/photo not found."]
end
if env["HTTP_ACCEPT"] == "application/json"
content_type :json
fn = nil
if /<title[^>]*>(?<title>[^<]+)<\/title>/ =~ response.body && /data-utime="(?<utime>\d+)"/ =~ response.body
title = title.force_encoding("UTF-8").gsub(" | Facebook", "")
created_time = Time.at(utime.to_i)
fn = "#{created_time.to_date} - #{title}.#{url.url_ext}".to_filename
end
return {
url: url,
filename: fn,
}.to_json
end
redirect url
end
end

get %r{/facebook/(?<id>\d+)/(?<username>.+)} do |id, username|
return [404, "Credentials not configured"] if !ENV["FACEBOOK_APP_ID"] || !ENV["FACEBOOK_APP_SECRET"]

@id = id
@type = @edge = %w[videos photos live].pick(params[:type]) || "posts"
@edge = "videos" if @type == "live"
fields = {
"posts" => "updated_time,from,parent_id,type,story,name,message,description,link,source,picture,full_picture,properties",
"videos" => "updated_time,from,title,description,embed_html,length,live_status",
"photos" => "updated_time,from,message,description,name,link,source",
}[@edge]

query = { fields: fields, since: Time.now.to_i-365*24*60*60 } # date -v -1w +%s

if params.has_key?(:locale)
query[:locale] = params[:locale]
end

response = Facebook.get("/#{id}/#{@edge}", query: query)
return [response.code, "#{Facebook::BASE_URL}/#{id}/#{@edge} returned code #{response.code}."] if response.code == 400
raise(FacebookError, response) if !response.success?

@data = response.json["data"]
if @edge == "posts"
# Copy down video length from properties array
@data.each do |post|
if post.has_key?("properties")
post["properties"].each do |prop|
if prop["name"] == "Length" && /^(?<m>\d+):(?<s>\d+)$/ =~ prop["text"]
post["length"] = 60*m.to_i + s.to_i
end
end
end
end
elsif @type == "live"
@data.select! { |post| post["live_status"] }
end

# Remove live videos from most feeds
if @type != "live"
@data.select! { |post| post["live_status"] != "LIVE" }
end

@user = @data[0]["from"]["name"] rescue CGI.unescape(username)
@title = @user
if @type == "live"
@title += "'s live videos"
elsif @type != "posts"
@title += "'s #{@type}"
end
@title += " on Facebook"

@data.map do |post|
post.slice("message", "description", "link").values.map(&:grep_urls)
end.flatten.tap { |urls| URL.resolve(urls) }

erb :"facebook.atom"
return [410, "Facebook functionality has been removed since I do not have API access. Maybe we can rebuild it some day, but using scraping techniques or something."]
end

get "/instagram" do
Expand Down
17 changes: 0 additions & 17 deletions app/facebook.rb

This file was deleted.

2 changes: 1 addition & 1 deletion config/initializers/05-string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def embed_html(request=nil)
if %r{^https?://www\.facebook\.com/.*/videos/(?:vb\.\d+\/)?(?<id>\d+)} =~ self || %r{^https?://www\.facebook\.com/video/embed\?video_id=(?<id>\d+)} =~ self
<<~EOF
<iframe width="1280" height="720" src="https://www.facebook.com/video/embed?video_id=#{id}" frameborder="0" scrolling="no" allowfullscreen referrerpolicy="no-referrer"></iframe>
<a href="https://www.facebook.com/video/embed?video_id=#{id}" rel="noreferrer">Open embed</a> | <a href="#{root_url}/facebook/download?url=#{id}">Download video</a> | <a href="#{root_url}/#{Addressable::URI.new(query: "download=https://www.facebook.com/video/embed?video_id=#{id}").normalize.to_s}">Download video with nice filename</a>
<a href="https://www.facebook.com/video/embed?video_id=#{id}" rel="noreferrer">Open embed</a>
EOF
elsif %r{^https?://(?:www\.|m\.)youtube\.com/(?:.*?[?&#](v=(?<id>[^&#]+)|list=(?<list>[^&#]+)|(?:t|time_continue)=(?<t>[^&#]+)))+} =~ self || %r{^https?://(?:youtu\.be|(?:www\.)?youtube\.com/embed)/(?<id>[^?&#]+)(?:.*?[?&#](list=(?<list>[^&#]+)|(?:t|time_continue)=(?<t>[^&#]+)))*} =~ self
# https://www.youtube.com/watch?v=z5OGD5_9cA0&list=PL0QrZvg7QIgpoLdNFnEePRrU-YJfr9Be7&index=3&t=30s
Expand Down
2 changes: 0 additions & 2 deletions kubernetes/configmap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ data:
# TWITTER_ACCESS_TOKEN: ""
# GOOGLE_API_KEY: ""
# VIMEO_ACCESS_TOKEN: ""
# FACEBOOK_APP_ID: ""
# FACEBOOK_APP_SECRET: ""
# SOUNDCLOUD_CLIENT_ID: ""
# TWITCH_CLIENT_ID: ""
# TWITCHTOKEN_CLIENT_ID: ""
Expand Down
87 changes: 0 additions & 87 deletions views/facebook.atom.erb

This file was deleted.

23 changes: 0 additions & 23 deletions views/index.erb
Original file line number Diff line number Diff line change
Expand Up @@ -92,29 +92,6 @@
</form>
<% end %>

<% if ENV["FACEBOOK_APP_ID"] && ENV["FACEBOOK_APP_SECRET"] %>
<form class="input-group" method="get" action="facebook">
<div class="input-group-prepend">
<span class="input-group-text"><label for="facebook_q">Facebook</label></span>
</div>
<input class="form-control" type="search" name="q" id="facebook_q" placeholder="Enter a Facebook page name or its url." required>
<div class="input-group-append">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" data-submit-type="">All posts (default)</a>
<a class="dropdown-item" data-submit-type="live">Live videos</a>
<a class="dropdown-item" data-submit-type="videos">Videos</a>
<a class="dropdown-item" data-submit-type="photos">Photos</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" data-download>Open video/photo</a>
<a class="dropdown-item" data-download download>Download video/photo</a>
<a class="dropdown-item" data-download-filename>Download video/photo with nice filename</a>
</div>
<input class="btn btn-primary" type="submit" value="Get RSS Feed">
</div>
</form>
<% end %>

<form class="input-group" method="get" action="instagram">
<div class="input-group-prepend">
<span class="input-group-text"><label for="instagram_q">Instagram</label></span>
Expand Down

0 comments on commit 5a0b18a

Please sign in to comment.