From 5a0b18a660c9d8971936f8ba9d34c8dc03954eb2 Mon Sep 17 00:00:00 2001 From: Stefan Sundin Date: Thu, 27 Aug 2020 23:54:46 -0700 Subject: [PATCH] Delete Facebook code. Discuss here: https://github.com/stefansundin/rssbox/issues/5. --- .dockerenv.example | 3 - .env.example | 3 - README.md | 6 +- Vagrantfile | 2 - app.json | 8 -- app.rb | 149 +------------------------------ app/facebook.rb | 17 ---- config/initializers/05-string.rb | 2 +- kubernetes/configmap.yml | 2 - views/facebook.atom.erb | 87 ------------------ views/index.erb | 23 ----- 11 files changed, 3 insertions(+), 299 deletions(-) delete mode 100644 app/facebook.rb delete mode 100644 views/facebook.atom.erb diff --git a/.dockerenv.example b/.dockerenv.example index 6f17362..9a5432f 100644 --- a/.dockerenv.example +++ b/.dockerenv.example @@ -6,9 +6,6 @@ REDIS_URL=redis://redis:6379 #VIMEO_ACCESS_TOKEN= -#FACEBOOK_APP_ID= -#FACEBOOK_APP_SECRET= - #SOUNDCLOUD_CLIENT_ID= #TWITCH_CLIENT_ID= diff --git a/.env.example b/.env.example index fcd0fd2..b30d273 100644 --- a/.env.example +++ b/.env.example @@ -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= diff --git a/README.md b/README.md index b2b5148..bde812c 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/Vagrantfile b/Vagrantfile index 7ab7ff3..6cd4490 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -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= diff --git a/app.json b/app.json index a1205c9..74ec392 100644 --- a/app.json +++ b/app.json @@ -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 diff --git a/app.rb b/app.rb index 9bba128..7f29be2 100644 --- a/app.rb +++ b/app.rb @@ -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] @@ -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=(?.+)$/ =~ 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\/[^\/]+\/(?\d+)/ =~ params[:q] - # https://www.facebook.com/pages/Lule%C3%A5-Sweden/106412259396611?fref=ts - elsif /facebook\.com\/groups\/(?\d+)/ =~ params[:q] - # https://www.facebook.com/groups/223764997793315 - elsif /facebook\.com\/video\/[^\d]+(?\d+)/ =~ params[:q] - # https://www.facebook.com/video/embed?video_id=1192228974143110 - elsif /facebook\.com\/[^\/]+-(?[\d]+)/ =~ params[:q] - # https://www.facebook.com/TNG-Recuts-867357396651373/ - elsif /facebook\.com\/(?:pg\/)?(?[^\/?#]+)/ =~ 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 /\/(?\d+)/ =~ params[:url] - # https://www.facebook.com/infectedmushroom/videos/10153430677732261/ - # https://www.facebook.com/infectedmushroom/videos/vb.8811047260/10153371214897261/?type=2&theater - elsif /\d+_(?\d+)/ =~ params[:url] - elsif /v=(?\d+)/ =~ params[:url] - elsif /(?\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)?:"(?[^"]+)"/ =~ 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>/ =~ 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 diff --git a/app/facebook.rb b/app/facebook.rb deleted file mode 100644 index 7dce215..0000000 --- a/app/facebook.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true -# https://developers.facebook.com/docs/graph-api/reference -# https://developers.facebook.com/docs/graph-api/changelog -# https://developers.facebook.com/docs/graph-api/changelog/breaking-changes - -class FacebookError < HTTPError; end - -class Facebook < HTTP - BASE_URL = "https://graph.facebook.com/v2.12" - PARAMS = "access_token=#{ENV["FACEBOOK_APP_ID"]}|#{ENV["FACEBOOK_APP_SECRET"]}" - ERROR_CLASS = FacebookError -end - -error FacebookError do |e| - status 503 - "There was a problem talking to Facebook. Please try again in a moment." -end diff --git a/config/initializers/05-string.rb b/config/initializers/05-string.rb index ecd9442..543ab80 100644 --- a/config/initializers/05-string.rb +++ b/config/initializers/05-string.rb @@ -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 diff --git a/kubernetes/configmap.yml b/kubernetes/configmap.yml index df9db7b..c42313c 100644 --- a/kubernetes/configmap.yml +++ b/kubernetes/configmap.yml @@ -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: "" diff --git a/views/facebook.atom.erb b/views/facebook.atom.erb deleted file mode 100644 index 6c0874e..0000000 --- a/views/facebook.atom.erb +++ /dev/null @@ -1,87 +0,0 @@ -<%- content_type :atom -%> -<?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom"> - <id>facebook:<%= @id %></id> - <title><%= @title %> - https://www.facebook.com/favicon.ico - - - <%= Time.parse(@data[0]["updated_time"]) if @data[0] %> -<%- -@data.each do |post| - id = post["id"] - id += ":#{post["live_status"]}" if post.has_key?("live_status") - /(^|_)(?\d+)$/ =~ (post["parent_id"] || post["id"]) - - type = if post.has_key?("type") - post["type"] - elsif %w[videos photos].include?(@post) - @type[0..-2] - else - @type - end - - post["link"] = URL.lookup(post["link"]) if post.has_key?("link") - post["link"] = "https://www.facebook.com/video/embed?video_id=#{object_id}" if @edge == "videos" || (post["type"] == "video" && post["link"].start_with?("https://www.facebook.com/")) - link = post["link"] || "https://www.facebook.com/#{post["id"]}" --%> - - - facebook:post:<%= id %><%= ":#{params[:cachebuster]}" if params[:cachebuster] %> - <%= -if (post.has_key?("live_status") && post["live_status"] != "VOD") || (post.has_key?("story") && post["story"].include?(" is live now")) - "[LIVE] " -elsif post.has_key?("length") - "[#{post["length"].round.to_duration}] " -end -%><%= -if @type == "posts" || @type == "videos" - prefix = if post.has_key?("live_status") || (post.has_key?("story") && post["story"].include?(" live")) - "Live" - elsif %w[link video photo event].include?(post["type"]) - post["type"].capitalize - end -end - -suffix = if post["title"] - post["title"].to_line.esc -elsif post["name"] - post["name"].to_line.esc -elsif post["message"] - post["message"].to_line.truncate(120).esc -elsif post["type"] == "link" - post["link"].esc -elsif post["description"] - post["description"].to_line.truncate(120).esc -end - -if prefix && suffix - "#{prefix}: #{suffix}" -elsif suffix || prefix - suffix || prefix -else - type.capitalize -end -%> - - <%= Time.parse(post["updated_time"]) %> - <%= post["from"]["name"].esc %> - -<%= "

#{post["story"]}

".esc if post.has_key?("story") %> -<%= post.slice("message", "description", "link").values.linkify_and_embed(request).to_paragraphs.esc %> -<%= -if type == "photo" && post.has_key?("source") - "

".esc -elsif type == "photo" - <<~EOF.esc -

-

Full size

- EOF -end -%> -<%= "

Link: #{post["link"]}

".esc if post.has_key?("link") %> -<%= "

Post: https://www.facebook.com/#{post["id"]}

".esc %> -
-
-<%- end -%> - diff --git a/views/index.erb b/views/index.erb index 45b153e..b302d0e 100644 --- a/views/index.erb +++ b/views/index.erb @@ -92,29 +92,6 @@ <% end %> -<% if ENV["FACEBOOK_APP_ID"] && ENV["FACEBOOK_APP_SECRET"] %> -
-
- -
- - -
-<% end %> -