Skip to content

Commit

Permalink
tidy up code
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Bishop committed Mar 27, 2018
1 parent f2c4770 commit 89a4376
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 241 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
*.mkv
*.gz
*.zip
.*.swp
vendor
youtubeuploader
141 changes: 141 additions & 0 deletions files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"

"google.golang.org/api/youtube/v3"
)

const outputDateLayout = "2006-01-02T15:04:05.000Z" //ISO 8601 (YYYY-MM-DDThh:mm:ss.sssZ)
const inputDateLayout = "2006-01-02"

type Date struct {
time.Time
}

func LoadVideoMeta(filename string, video *youtube.Video) (videoMeta VideoMeta) {
// attempt to load from meta JSON, otherwise use values specified from command line flags
if filename != "" {
file, e := ioutil.ReadFile(filename)
if e != nil {
fmt.Printf("Could not read filename file '%s': %s\n", filename, e)
fmt.Println("Will use command line flags instead")
goto errJump
}

e = json.Unmarshal(file, &videoMeta)
if e != nil {
fmt.Printf("Could not read filename file '%s': %s\n", filename, e)
fmt.Println("Will use command line flags instead")
goto errJump
}

video.Snippet.Tags = videoMeta.Tags
video.Snippet.Title = videoMeta.Title
video.Snippet.Description = videoMeta.Description
video.Snippet.CategoryId = videoMeta.CategoryId
if videoMeta.PrivacyStatus != "" {
video.Status.PrivacyStatus = videoMeta.PrivacyStatus
}
if videoMeta.Location != nil {
video.RecordingDetails.Location = videoMeta.Location
}
if videoMeta.LocationDescription != "" {
video.RecordingDetails.LocationDescription = videoMeta.LocationDescription
}
if !videoMeta.RecordingDate.IsZero() {
video.RecordingDetails.RecordingDate = videoMeta.RecordingDate.Format(outputDateLayout)
}
if videoMeta.Language != "" {
video.Snippet.DefaultLanguage = videoMeta.Language
video.Snippet.DefaultAudioLanguage = videoMeta.Language
}
}
errJump:

if video.Status.PrivacyStatus == "" {
video.Status = &youtube.VideoStatus{PrivacyStatus: *privacy}
}
if video.Snippet.Tags == nil && strings.Trim(*tags, "") != "" {
video.Snippet.Tags = strings.Split(*tags, ",")
}
if video.Snippet.Title == "" {
video.Snippet.Title = *title
}
if video.Snippet.Description == "" {
video.Snippet.Description = *description
}
if video.Snippet.CategoryId == "" && *categoryId != "" {
video.Snippet.CategoryId = *categoryId
}

return
}

func Open(filename string) (reader io.ReadCloser, filesize int64) {
if strings.HasPrefix(filename, "http") {
resp, err := http.Head(filename)
if err != nil {
log.Fatalf("Error opening %s: %s", filename, err)
}
lenStr := resp.Header.Get("content-length")
if lenStr != "" {
filesize, err = strconv.ParseInt(lenStr, 10, 64)
if err != nil {
log.Fatal(err)
}
}

resp, err = http.Get(filename)
if err != nil {
log.Fatalf("Error opening %s: %s", filename, err)
}
if resp.ContentLength != 0 {
filesize = resp.ContentLength
}
reader = resp.Body
return
}

file, err := os.Open(filename)
if err != nil {
log.Fatalf("Error opening %s: %s", filename, err)
}

fileInfo, err := file.Stat()
if err != nil {
log.Fatalf("Error stat'ing file %s: %s", filename, err)
}

return file, fileInfo.Size()
}

func (d *Date) UnmarshalJSON(b []byte) (err error) {
s := string(b)
s = s[1 : len(s)-1]
d.Time, err = time.Parse(inputDateLayout, s)
return
}
120 changes: 120 additions & 0 deletions http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"fmt"
"io/ioutil"
"net/http"

"github.com/porjo/go-flowrate/flowrate"
"google.golang.org/api/youtube/v3"
)

type limitTransport struct {
rt http.RoundTripper
reader *flowrate.Reader
filesize int64
}

type VideoMeta struct {
// snippet
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
CategoryId string `json:"categoryId,omitempty"`
Tags []string `json:"tags,omitempty"`

// status
PrivacyStatus string `json:"privacyStatus,omitempty"`
Embeddable bool `json:"embeddable,omitempty"`
License string `json:"license,omitempty"`
PublicStatsViewable bool `json:"publicStatsViewable,omitempty"`
PublishAt string `json:"publishAt,omitempty"`

// recording details
Location *youtube.GeoPoint `json:"location,omitempty"`
LocationDescription string `json:"locationDescription, omitempty"`
RecordingDate Date `json:"recordingDate, omitempty"`

// single playistID retained for backwards compatibility
PlaylistID string `json:"playlistId, omitempty"`
PlaylistIDs []string `json:"playlistIds, omitempty"`

// BCP-47 language code e.g. 'en','es'
Language string `json:"language, omitempty"`
}

func (t *limitTransport) RoundTrip(r *http.Request) (res *http.Response, err error) {
// FIXME need a better way to detect which roundtrip is the media upload
if r.ContentLength > 1000 {
var monitor *flowrate.Monitor

if t.reader != nil {
monitor = t.reader.Monitor
}

// kbit/s to B/s = 1000/8 = 125
t.reader = flowrate.NewReader(r.Body, int64(*rate*125))

if monitor != nil {
// carry over stats to new limiter
t.reader.Monitor = monitor
} else {
t.reader.Monitor.SetTransferSize(t.filesize)
}
r.Body = ioutil.NopCloser(t.reader)
}

return t.rt.RoundTrip(r)
}

func AddVideoToPlaylist(service *youtube.Service, playlistID, videoID string) (err error) {
listCall := service.Playlists.List("snippet,contentDetails")
listCall = listCall.Mine(true)
response, err := listCall.Do()
if err != nil {
return fmt.Errorf("error retrieving playlists: %s", err)
}

var playlist *youtube.Playlist
for _, pl := range response.Items {
if pl.Id == playlistID {
playlist = pl
break
}
}

// TODO: handle creation of playlist
if playlist == nil {
return fmt.Errorf("playlist ID '%s' doesn't exist", playlistID)
}

playlistItem := &youtube.PlaylistItem{}
playlistItem.Snippet = &youtube.PlaylistItemSnippet{PlaylistId: playlist.Id}
playlistItem.Snippet.ResourceId = &youtube.ResourceId{
VideoId: videoID,
Kind: "youtube#video",
}

insertCall := service.PlaylistItems.Insert("snippet", playlistItem)
_, err = insertCall.Do()
if err != nil {
return fmt.Errorf("error inserting video into playlist: %s", err)
}

fmt.Printf("Video added to playlist '%s' (%s)\n", playlist.Snippet.Title, playlist.Id)

return nil
}
48 changes: 48 additions & 0 deletions progress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"fmt"
"strings"
"time"
)

func Progress(quitChan chanChan, transport *limitTransport, filesize int64) {
ticker := time.Tick(time.Second)
var erase int
for {
select {
case <-ticker:
if transport.reader != nil {
s := transport.reader.Monitor.Status()
curRate := float32(s.CurRate)
var status string
if curRate >= 125000 {
status = fmt.Sprintf("Progress: %8.2f Mbps, %d / %d (%s) ETA %8s", curRate/125000, s.Bytes, filesize, s.Progress, s.TimeRem)
} else {
status = fmt.Sprintf("Progress: %8.2f kbps, %d / %d (%s) ETA %8s", curRate/125, s.Bytes, filesize, s.Progress, s.TimeRem)
}
fmt.Printf("\r%s\r%s", strings.Repeat(" ", erase), status)
erase = len(status)
}
case ch := <-quitChan:
// final newline
fmt.Println()
close(ch)
return
}
}
}
Loading

0 comments on commit 89a4376

Please sign in to comment.