Skip to content

Commit

Permalink
serve as sideloading server so no need to manually install the app
Browse files Browse the repository at this point in the history
  • Loading branch information
David Tahir committed Dec 23, 2020
1 parent 7fbf2c2 commit 206e9dc
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 10 deletions.
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,32 @@ Proxy Server for older Samsung Smart-TVs (E/F - Series) which only support TLS u

## Installation

### Preparing the Proxy

Download the corresponding binary for your system from the [latest releases](https://github.com/kadrim/proxy4plex/releases/latest) and run it. You might want to run the binary on system start. This is different for each system but in the future the proxy will install itself if needed.

### Preparing the Smart-TV

- Download the latest version of Orca's Plex-App for Samsung TVs from here https://www.dropbox.com/s/f17hx2w7tvofjqr/Plex_2.014_11112020.zip?dl=1
- Install it using USB-Sideloading or via SammyWidgets
- Check this thread if you need more information: https://forums.plex.tv/t/samsung-tv-cannot-connect-to-plex/650100/8
#### Using proxy4plex as sideloader

### Preparing the Proxy
Notice: this will only work, if the system you are running on, is on the same network as your TV and has not yet a service running on Port 80, because this is needed by the TV to download new Apps. I.e: This will not work on non-rooted Android Phones, as the Port 80 is blocked. Running the proxy on non-rooted Android phones does work. So the initial Setup has do be done via another machine.

Download the corresponding binary for your system from the [latest releases](https://github.com/kadrim/proxy4plex/releases/latest) and run it. You might want to run the binary on system start. This is different for each system but in the future the proxy will install itself if needed.
This process has only to be done once. So after the app has been installed via this method, it stays on the TV!

1. Start the `proxy4plex` binary
2. Open `smarthub` on your TV
3. Hit the `Red` button on the remote to login to an account
4. Use `develop` for username, password should fill automatically, if it does not, use `111111`
5. Hit the `Tools` button on the remote and select `Settings` while within `smarthub`
6. Select the menu-entry `Development` and accept the agreement after reading it
7. Select `Server-IP-Settings` and enter the local IP-Adress of your machine running `proxy4plex`
8. Select `Synchronize` and the app will be installed permanentely on the TV

#### Manual sideloading

1. Download the latest version of Orca's Plex-App for Samsung TVs from here https://www.dropbox.com/s/f17hx2w7tvofjqr/Plex_2.014_11112020.zip?dl=1
2. Install it using USB-Sideloading or via SammyWidgets
3. Check this thread if you need more information: https://forums.plex.tv/t/samsung-tv-cannot-connect-to-plex/650100/8

### Putting it together

Expand All @@ -38,6 +55,8 @@ On Android this package is currently not yet available as native app. Neverthele

After that you can use the IP-Adress of your android device for your Plex-App on the TV. If you close termux or reboot your device you can simply re-run the proxy by starting termux and then starting the proxy via the command `proxy4plex/proxy4plex`

Beware: Sideloading (i.e. installing the app on the TV) does not work this way, because non-rooted Android devices are not allowed to use Port 80

## Compiling

At the time of writing, this package needs at least [golang](https://golang.org/) v1.15
Expand All @@ -51,7 +70,6 @@ To compile for all possible architectures you can run the command `go-build-all.
## TODOs

- detect OS and allow User to install the proxy as a boot-service
- serve as sideloading server so no need to manually run SammyWidgets
- porting to Android and iOS as native apps
- auto-update notifications

Expand Down
148 changes: 144 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
package main

import (
"archive/zip"
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
"regexp"
"strconv"
)

const (
port = "3000"
server = "http://plex.tv"
port = "3000"
server = "http://plex.tv"
officialAppURL = "https://www.dropbox.com/s/f17hx2w7tvofjqr/Plex_2.014_11112020.zip?dl=1"
officialAppChksum = "8c6b2bb25a4c2492fd5dbde885946dcb6b781ba292e5038239559fd7a20e707e"
modifiedAppName = "Plex_2.014_net"
modifiedAppFile = "Plex_2.014_11112020_net.zip"
)

var modifiedBuffer []byte

type transport struct {
http.RoundTripper
}
Expand Down Expand Up @@ -66,15 +81,140 @@ func handleRequest(res http.ResponseWriter, req *http.Request) {
proxy.ServeHTTP(res, req)
}

func extractZipFile(zipFile *zip.File) ([]byte, error) {
file, err := zipFile.Open()
if err != nil {
return nil, err
}
defer file.Close()
return ioutil.ReadAll(file)
}

func retreiveZipFile() ([]byte, error) {
// only retreive data once
if modifiedBuffer != nil {
return modifiedBuffer, nil
}

// download the original zip
resp, err := http.Get(officialAppURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

// checksum
chksum := sha256.Sum256(body)
if hex.EncodeToString(chksum[:]) == officialAppChksum {
log.Println("Checksum match. Going on ...")
} else {
err := errors.New("Checksum did not match, aborting")
return nil, err
}

// attach the zipWriter to the buffer
buf := new(bytes.Buffer)
w := zip.NewWriter(buf)

// create zipReader
zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
if err != nil {
return nil, err
}

// regexp pattern to remove first directory
regex := regexp.MustCompile(`^Plex/`)

// process all files, read each file and write it to new zip
for _, zipFile := range zipReader.File {
fmt.Println("Processing file:", zipFile.Name)
newFileName := regex.ReplaceAllString(zipFile.Name, "")
fmt.Println("Replacement:", newFileName)
bytes, err := extractZipFile(zipFile)
if err != nil {
return nil, err
}

// write file to new zip
file, err := w.Create(newFileName)
if err != nil {
return nil, err
}
_, err = file.Write(bytes)
if err != nil {
return nil, err
}
}

err = w.Close()
if err != nil {
return nil, err
}

// write data to global var
modifiedBuffer = buf.Bytes()

return modifiedBuffer, nil
}

func main() {
// handle simple information path
http.HandleFunc("/info", func(res http.ResponseWriter, req *http.Request) {
res.Write([]byte("The Plex proxy service is running"))
res.Write([]byte("The Plex proxy service is running on " + req.Host))
})

// start real server
//handle widgetlist for sideloading
http.HandleFunc("/widgetlist.xml", func(res http.ResponseWriter, req *http.Request) {
buf, err := retreiveZipFile()
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
res.Write([]byte(err.Error()))
log.Println(err)
return
}
xml := `<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
<list>
<widget id="` + modifiedAppName + `">
<title>Plex</title>
<compression size="` + strconv.Itoa(len(buf)) + `" type="zip"/>
<description/>
<download>http://` + req.Host + `/` + modifiedAppFile + `</download>
</widget>
</list>
</rsp>`

res.Write([]byte(xml))
})

// handle app-deployment
http.HandleFunc("/"+modifiedAppFile, func(res http.ResponseWriter, req *http.Request) {
buf, err := retreiveZipFile()
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
res.Write([]byte(err.Error()))
log.Println(err)
return
}
// write the http-response
res.Write(buf)
})

// start real proxy
http.HandleFunc("/", handleRequest)

// try to handle everything on port 80 aswell for serving the app
// Note: this will not work on non-rooted android because only high-ports can be used
go func() {
log.Println("Trying to start app-deployer on port 80 ...")
http.ListenAndServe(":80", nil)
}()

log.Println("Server starting on Port " + port + " ...")
log.Fatal(http.ListenAndServe(":"+port, nil))
}

0 comments on commit 206e9dc

Please sign in to comment.